source("../Rscripts/BaseScripts.R")
library(cowplot)

1 Estiamte SFS with all individuals and all sites

(estimated by each chromosome and combine them later) (5.26.22~)

Step 1: Run PWS07_sfs_step1.sh (in “/Data/Slurumscripts/SFS_fromBam/PWS07_sfs_step1.sh”) for each population (takes a long time to create a saf file)

Step 2: Run PWS07_sfs_step2.sh to create unfolded sfs for each chromosome (Can’t run the whole genome due to memory constraints)

Step 2.2: Run PWS07_sfs_step2_folded.sh to create folded sfs for each chromosome

Step 3: Run R scripts to combine all sfs into 1

# at FARM, run the following scripts to combine sfs files
module load R
R
source("combineSFSfold.R") 
source("combineSFSunfold.R") 
combineSFSunfold("PWS07")   # this will create a "PWS07_unfolded.sfs" in /home/ktist/ph/data/angsd/SFS/fromBam/
combineSFSfold("PWS07")   # this will create a "PWS07_folded.sfs" in /home/ktist/ph/data/angsd/SFS/fromBam/folded/

#Exit R by typing 
quit()
/var/folders/w_/cgjdhjtn7xsd36t28tkzxcqr0000gn/T/RtmphHWSq0/chunk-code-62f153daa41.txt: line 2: module: command not found
Fatal error: you must specify '--save', '--no-save' or '--vanilla'

Locally, you can run here:

combineSFSfold<-function(pop){
    ch1<-scan(paste0("Data/new_vcf/angsd/fromBam/folded/",pop,"_folded_chr1.sfs"))
    pws.sfs<-data.frame(chr1=ch1)
    for (i in 2:26){
        vec<-scan(paste0("Data/new_vcf/angsd/fromBam/folded/",pop,"_folded_chr",i,".sfs"))
        pws.sfs[,paste0("chr",i)]<-vec
    }
    pws.sfs$sum<-rowSums(pws.sfs)
    sink(paste0("Data/new_vcf/angsd/fromBam/folded/",pop,"_folded.sfs"))
    cat(pws.sfs$sum)
    sink(NULL)
}

combineSFSunfold<-function(pop){
    ch1<-scan(paste0("Data/new_vcf/angsd/fromBam/unfolded/",pop,"_unfolded_chr1.sfs"))
    pws.sfs<-data.frame(chr1=ch1)
    for (i in 2:26){
        vec<-scan(paste0("Data/new_vcf/angsd/fromBam/unfolded/",pop,"_unfolded_chr",i,".sfs"))
        pws.sfs[,paste0("chr",i)]<-vec
    }
    pws.sfs$sum<-rowSums(pws.sfs)
    sink(paste0("Data/new_vcf/angsd/fromBam/unfolded/",pop,"_unfolded.sfs"))
    cat(pws.sfs$sum)
    sink(NULL)
}

#Run with the 'pop' identifier
combineSFSunfold("PWS07")
Error in file(file, "r") : cannot open the connection

Step 4: Run PWS07_sfs_theta.sh to calculate theta and Tajima’s D for unfolded.sfs (Fay & Wu’s H should be used with unfolded sfs)

Step 4.2: Run PWS07_sfs_step3_folded.sh to calculate theta and Tajima’s D for folded.sfs (Tajima’s D should be used with folded sfs)

1.1 SFS from bam files

1.1.1 1DSFS PWS


source("../Rscripts/BaseScripts.R")
pops<-c("PWS91","PWS96","PWS07","PWS17")

sfs1D<-data.frame()
for (i in 1:length(pops)){
    sfs <- scan(paste0("../Data/new_vcf/angsd/fromBam/combined/",pops[i],"_unfolded.sfs"))
    sfs1 <- data.frame(ac=sfs)
    sfs1$count<-0:(nrow(sfs1)-1)
    #remove the invariable sites
    sfs1<-sfs1[-c(1,nrow(sfs1)),]
    sfs1$pop<-pops[i]
    sfs1D<-rbind(sfs1D, sfs1)
}
    
sfs1D$pop<-factor(sfs1D$pop, levels=pops)
ggplot(data=sfs1D, aes(x=count, y=ac))+
    facet_wrap(~pop, ncol=4)+
        geom_bar(stat="identity", color="gray")+xlab("Frequency bin")+ ylab("Number of alleles")+
        theme_classic()+
        scale_y_continuous(labels=scales::comma)+
        theme(strip.background = element_rect(
            color="black", fill="gray80", size=0.5, linetype="solid"))
ggsave("../Output/SFS/1DSFS_fromBam_PWS.png", width = 11, height = 2.2, dpi=300)

1.1.2 Pi (π)

pops<-c("PWS91","PWS96","PWS07","PWS17")
theta<-data.frame()
for (i in 1:length(pops)){
    theta2<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/',pops[i],'_50kwin_10kstep.pestPG'))
    theta2$pi<-theta2$tP/theta2$nSites
    df<-theta2[,c("Chr","WinCenter","pi","fayh" )]
    df$pop<-pops[i]    
    theta<-rbind(theta, df)
}

#mean pi and Fay's H  (from unfolded SFS)
theta$pop<-factor(theta$pop, levels=pops)

ggplot(theta, aes(x=pop, y=pi))+
    geom_boxplot(position=position_dodge(width = 0.8), color=blu, outlier.alpha = 0.6,outlier.size = 0.7,width=0.6)+
    geom_point(stat = "summary", fun = "mean",position=position_dodge(width = 0.8))+
    ylab(expression(pi))+xlab("")+
    theme_bw()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5,2.5,3.5), color="gray", size=0.5)
ggsave("../Output/SFS/Pi_estimates_PWS_fromBam.png", width = 5, height = 3.5)

1.1.3 Fay’s H

ggplot(theta, aes(x=pop, y=fayh))+
    geom_boxplot(position=position_dodge(width = 0.8), color=grb, outlier.alpha = 0.6,outlier.size = 0.7,width=0.6)+
    geom_point(stat = "summary", fun = "mean",position=position_dodge(width = 0.8))+
    ylab("Fay's H")+xlab("")+
    theme_bw()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5,2.5,3.5), color="gray", size=0.5)
ggsave("../Output/SFS/FayH_estimates_PWS_fromBam.png", width = 5, height = 3.5)

1.1.4 Tajima’s D


#Tajima's D (folded SFS)
theta<-data.frame()
for (i in 1:length(pops)){
    theta2<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/folded/',pops[i],'_50kwin_10kstep.pestPG'))
    df<-theta2[,c("Chr","WinCenter","Tajima" )]
    df$pop<-pops[i]    
    theta<-rbind(theta, df)
}

theta$pop<-factor(theta$pop, levels=pops)
ggplot(theta, aes(x=pop, y=Tajima))+
    geom_boxplot(position=position_dodge(width = 0.8), color=org, outlier.alpha = 0.6,outlier.size = 0.7,width=0.6)+
    geom_point(stat = "summary", fun = "mean",position=position_dodge(width = 0.8))+
    ylab("Tajima's D")+xlab("")+
    theme_bw()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5,2.5,3.5), color="gray", size=0.5)
ggsave("../Output/SFS/TajimaD_PWS_fromBam.png", width = 5, height = 3.5)

1.2 Estimate SFS from VCF files

(Using maf0.00 -no low allele freq cutoff)

Step 1: Run BC17_angsd_SFS.sh (in “/Data/Slurumscripts/SFS_fromVCFmaf00/”) for each population - this will calculate sfs, theta for both folded and unfolded SFS.

Step 2: Create 2D SFS by running each combination (ex. BC17CA172DSFS.sh in “/Data/Slurumscripts/SFS_fromVCFmaf00/”)

Step 3: Calculate Fst/Pbs for population combinations by running 3DFst scripts (ex. 3DFst_pws1.sh)

#Plot 2D SFS (Sfs_comparison.R)
source("../Rscripts/BaseScripts.R")

## 2D SFS
# The output from ANGSD is a flatten matrix: each value is the count of sites with the corresponding joint frequency ordered as
# [0,0] [0,1] [0,2] ..

# function to create a matrix from ANGSD output (a flatten matrix)
vec2mat<-function(vec, n1,n2, pop1, pop2){
    n1<-n1
    n2<-n2
    pop1<-pop1
    pop2<-pop2
    ANGSD.2D.SFS <- scan(paste(vec, sep=""), quiet=T)
    ANGSD.2D.SFS <- t(matrix(ANGSD.2D.SFS, nrow=n2*2+1, ncol=n1*2+1))
    # mask non-variant sites
    ANGSD.2D.SFS[1,1] <- 0
    ANGSD.2D.SFS[nrow(ANGSD.2D.SFS),ncol(ANGSD.2D.SFS)] <- 0
    df<-data.frame(ANGSD.2D.SFS)
    colnames(df)<-0:(ncol(df)-1)
    df$count<-0:(nrow(df)-1)
    return(df)
}

#Plot 2D SFS heatmap     
pops.info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops.info$yr<-''
pops.info$yr[pops.info$year==96|pops.info$year==91]<-paste0(19,pops.info$year[pops.info$year==96|pops.info$year==91])
pops.info$yr[pops.info$year==07|pops.info$year==06|pops.info$year==17]<-paste0(20,pops.info$year[pops.info$year==07|pops.info$year==06|pops.info$year==17])
pops.info$yr<-apply(pops.info["yr"], 1, function(x) {if(x==206) x=2006
                                        if (x==207) x=2007
                                        else x=x})
pops.info$yr<-as.integer(pops.info$yr)
pops<-unique(pops.info$Population.Year)

pwss<-c("PWS91","PWS96","PWS07","PWS17")
tbs<-c("TB91","TB96","TB06","TB17")
sss<-c("SS96","SS06","SS17")
y17<-pops[grep("17",pops)]
comb1<-combn(pwss, 2)
comb1<-t(comb1)
comb2<-combn(tbs, 2)
comb2<-t(comb2)
comb3<-combn(sss, 2)
comb3<-t(comb3)
comb4<-combn(y17, 2)
comb4<-t(comb4)

#https://stackoverflow.com/questions/49689069/heatmap-with-continuous-rainbow-colours
cols <- rev(rainbow(7)[-7]) #rainbow colors for heatmap

#PWS
Plots<-list()
sfs.pws<-data.frame()
for (i in 1: nrow(comb1)){
    pop1<-comb1[i,1]
    pop2<-comb1[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    
    if (pops.info$yr[pops.info$Population.Year==pop1][1]>pops.info$yr[pops.info$Population.Year==pop2][1]){
        sfs1<-data.frame(t(sfs1[,1:(ncol(sfs1)-1)]))
        colnames(sfs1)<-0:(ncol(sfs1)-1)
        sfs1$count<-0:(nrow(sfs1)-1)
        p2<-pop2
        pop2<-pop1
        pop1<-p2
    }
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs.pws<-rbind(sfs.pws, sfsm2)
}

sfs.pws$pop1<-factor(sfs.pws$pop1, levels=c("PWS91","PWS96","PWS07","PWS17"))
sfs.pws$pop2<-factor(sfs.pws$pop2, levels=c("PWS91","PWS96","PWS07","PWS17"))

ggplot(sfs.pws, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log10(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_PWS.png", width = 10, height = 8, dpi=300)
   

#TB
sfs.tb<-data.frame()
for (i in 1: nrow(comb2)){
    pop1<-comb2[i,1]
    pop2<-comb2[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    
    if (pops.info$yr[pops.info$Population.Year==pop1][1]>pops.info$yr[pops.info$Population.Year==pop2][1]){
        sfs1<-data.frame(t(sfs1[,1:(ncol(sfs1)-1)]))
        colnames(sfs1)<-0:(ncol(sfs1)-1)
        sfs1$count<-0:(nrow(sfs1)-1)
        p2<-pop2
        pop2<-pop1
        pop1<-p2
    }
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs.tb<-rbind(sfs.tb, sfsm2)
}

sfs.tb$pop1<-factor(sfs.tb$pop1, levels=c("TB91","TB96","TB06","TB17"))
sfs.tb$pop2<-factor(sfs.tb$pop2, levels=c("TB91","TB96","TB06","TB17"))

ggplot(sfs.tb, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log10(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_TB.png", width = 10, height = 8, dpi=300)

#SS
sfs.ss<-data.frame()
for (i in 1: nrow(comb3)){
    pop1<-comb3[i,1]
    pop2<-comb3[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    if (pops.info$yr[pops.info$Population.Year==pop1][1]>pops.info$yr[pops.info$Population.Year==pop2][1]){
        sfs1<-data.frame(t(sfs1[,1:(ncol(sfs1)-1)]))
        colnames(sfs1)<-0:(ncol(sfs1)-1)
        sfs1$count<-0:(nrow(sfs1)-1)
        p2<-pop2
        pop2<-pop1
        pop1<-p2
    }
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs.ss<-rbind(sfs.ss, sfsm2)
}
sfs.ss$pop1<-factor(sfs.ss$pop1, levels=c("SS96","SS06","SS17"))
sfs.ss$pop2<-factor(sfs.ss$pop2, levels=c("SS96","SS06","SS17"))

ggplot(sfs.ss, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_SS.png", width = 10, height = 8, dpi=300)

#2017 pops
sfs17<-data.frame()
for (i in 1: nrow(comb4)){
    pop1<-comb4[i,1]
    pop2<-comb4[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs17<-rbind(sfs17, sfsm2)
}

sfs17$pop1<-factor(sfs17$pop1, levels=paste(y17))
sfs17$pop2<-factor(sfs17$pop2, levels=paste(y17))

ggplot(sfs17, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_2017.png", width = 20, height = 16, dpi=300)

1.2.1 1D SFS all populations (Downsampled bam files)

1.2.2 2D SFS PWS

1.2.3 2D SFS TB

1.2.4 2D SFS SS

1.2.5 2D SFS (2017)

2 Fst between years per population

2.1 PWS

2.1.1 Fst along the genome

Pairwise Fst along the genome
### Pairwise Fst along each chromosome

## Plot Fst values along each chromosome
fst$chr<-factor(fst$chr, levels=paste0("chr",1:26))
fstpw<-fst
plots<-list()
compare<-paste0(unique(fstpw$pop))
max(fstpw$Fst)
for (i in 1:6){ 
    fs<-gsub("vs.","",compare[i])
    pops <- unlist(strsplit(fs, "\\."))
    maxy<-max(fstpw$Fst[fstpw$pop==compare[i]])
    # Fst with actual line to highlight the differences
    plots[[i]] <- ggplot(fstpw[fstpw$pop==compare[i],], aes(x =midPos, y =Fst )) + 
        geom_point(size = 1, color = gry,alpha = 0.4, shape = 1)+
        theme_minimal()+ylim(0,maxy+0.02)+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color=blu, size=0.2)+
        facet_wrap(~chr, ncol = 9)
}
#save the plots together
{png(paste0("../Output/SFS/PWS_Fst_maf00_chr.png"), height = 8, width = 18, res=150, units = "in")
grid.arrange(plots[[3]], plots[[2]], plots[[4]], plots[[1]],plots[[5]],plots[[6]], ncol=3)
dev.off()}

Pairwise Fst for each genome

2.1.2 Create pairwise Fst matrix

PWS Pairwise Fst

fsts2$time<-1
Error in `$<-.data.frame`(`*tmp*`, time, value = 1) : 
  replacement has 1 row, data has 0

2.1.3 Plot mean Fst for each chromosome

# Plot mean Fst of each chromosme
Fst<-data.frame()
compare<-paste0(unique(fstpw$pop))
for (j in 1:26){
    fst.ch<-fst[fst$ch==j,]
    pairch<-data.frame(matrix(ncol=4, nrow=4), row.names=pops)
    colnames(pairch)<-pops
    for (i in 1:6){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        df<-fst.ch[fst.ch$pop==compare[i],]
        pairch[pop1,pop2]<-mean(df$Fst, na.rm=T)
    }
    diag(pairch)<-0
    pairch$pop<-rownames(pairch)
    dfm<-melt(pairch,na.rm=T, id.vars='pop')
    
    #NA to diagonal
    dfm$value[dfm$value==0]<-NA
    dfm$pop<-factor(dfm$pop, levels=pops)
    dfm$value<-round(dfm$value, 4)
    dfm$chr<-j
    Fst<-rbind(Fst, dfm)
    
}
Fst$id<-paste0(Fst$pop," vs.",Fst$variable)
Fst<-Fst[!is.na(Fst$value),]
ggplot(Fst, aes(x=chr, y=value,color=id))+
    geom_point()+
    geom_path(stat="identity")+
    theme_minimal()+ylab("Fst")+
    scale_x_continuous(breaks=1:26, labels = 1:26)+
    theme(legend.title = element_blank(), panel.grid.minor.x = element_blank())
ggsave("../Output/SFS/PWS_Fst_byChromosome_dotplot.png", width = 8, height=4.5, dpi=150)

PWS average Fst per chromosome


2.2 Togiak Bay

2.2.1 Pairwise Fst along the genome

2.2.2 Pairwise Fst along each chromosome

#To save the plots, run in R
png(paste0("Output/SFS/TB_Fst_maf00_chr.png"), height = 8, width = 18, res=150, units = "in")  
grid.arrange(plots[[3]], plots[[2]], plots[[4]], plots[[1]],plots[[5]],plots[[6]], ncol=3)  
dev.off()  

2.2.3 Pairwise Fst matrix

## Continued from the above
pops<-c("TB91","TB96","TB06","TB17")
comb<-t(combn(pops,2))

## Plot average fst in a heatmap
compare<-unique(fst$pop)
pairfst<-data.frame(matrix(ncol=4, nrow=4), row.names=pops)
colnames(pairfst)<-pops
for (i in 1:6){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-fst[fst$pop==compare[i],]
    pairfst[pop1,pop2]<-mean(df$Fst, na.rm=T)
}
write.csv(pairfst,"../Output/SFS/TB_pairwiseFst_matrix.csv")

#pairfst<-read.csv("../Output/SFS/TB_pairwiseFst_matrix.csv", row.names = 1)

df<-pairfst
diag(df)<-0
df$pop<-rownames(df)
dfm<-melt(df,na.rm=T, id.vars='pop')
#NA to diagonal
dfm$value[dfm$value==0]<-NA
dfm$pop<-factor(dfm$pop, levels=pops)
dfm$value<-round(dfm$value, 4)
ggplot(data = dfm, aes(pop, variable, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FF"), limits=c(0, (max(dfm$value, na.rm=T)+0.005)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(pop, variable, label = value), color = "black", size = 5)
ggsave(paste0("../Output/SFS/pairwiseFst_TB.png"), width = 5, height = 5, dpi=150)

# Plot Fst in a bar plot ordered and colored in the same way as Fst/Pi shuffle results (Shuffling_pi.fst.tehat.Rmd)
fsts<-dfm[!is.na(dfm$value),]
fsts$comp<-paste0(fsts$pop,"_",fsts$variable)

#set the colors
#div1<-diverging_hcl(6, palette="Blue-Red")
#div2<-rev(div1)
#names(div2)<-c("PWS96_PWS07","PWS07_PWS17","PWS91_PWS96", "PWS91_PWS07", "PWS91_PWS17","PWS96_PWS17")
fsts<-fsts[order(fsts$value, decreasing = T),]
fsts$comp<-factor(fsts$comp, levels=paste0(unique(fsts$comp)))

ggplot(fsts, aes(x=comp, y=value, fill=comp))+
    geom_bar(stat="identity")+
    scale_fill_manual(values = div1)+
    xlab('')+ylab('Fst')+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())
ggsave("../Output/Fst/TB_PairwiseFst_ordered.png", width = 4, height = 2.8, dpi=300 )

#Fst over time
fsts2<-fsts[fsts$comp %in% c("TB91_TB96","TB96_TB06","TB06_TB17"),]
fsts2$time<-1
fsts2$time[fsts2$comp=="TB96_TB06"]<-2
fsts2$time[fsts2$comp=="TB06_TB17"]<-3
fsts2<-fsts2[order(fsts2$time),]
ggplot(fsts2, aes(x=time, y=value))+
    geom_point(size=3, color="steelblue")+
    geom_path( aes(x=time, y=value),color="steelblue")+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))
ggsave("../Output/Fst/Fst_overTime_TB.png", width = 4, height = 2.8, dpi=300 )

fsts$series<-"1991-2007, 1991-2017"
fsts$series[fsts$comp %in% c("TB91_TB96","TB96_TB06","TB06_TB17")]<-"1991-1996, 1996-2007, 2007-2017"
fsts$series[fsts$comp =="TB96_TB17"]<-"1996-2017"
fsts$time<-1
fsts$time[fsts$variable=="TB17"]<-3
fsts$time[fsts$variable=="TB06"]<-2
#source("../Rscripts/BaseScripts.R")
fsts<-fsts[order(fsts$time),]
ggplot(fsts, aes(x=time, y=value, color=series))+
    geom_point(size=3)+
    geom_path()+
    scale_color_manual(values=cols)+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "~2007","~2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_TB_allComparison.png", width = 6, height = 2.8, dpi=300 )

# plot both PWS and TB together

fstP2$pop<-"PWS"
fsts2$pop<-"TB"
fstPT<-rbind(fstP2, fsts2)

ggplot(fstPT, aes(x=time, y=value, color=pop))+
    geom_point(size=3)+
    geom_path( aes(x=time, y=value))+
    scale_color_manual(values=cols[c(2,1)])+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_PWS_TB.png", width = 4, height = 2.8, dpi=300 )

{width=64%]

2.2.4 Mean pairsie Fst per chromosome

# Plot mean Fst of each chromosme
Fst<-data.frame()
for (j in 1:26){
    fst.ch<-fst[fst$ch==j,]
    pairch<-data.frame(matrix(ncol=4, nrow=4), row.names=pops)
    colnames(pairch)<-pops
    for (i in 1:6){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        df<-fst.ch[fst.ch$pop==compare[i],]
        pairch[pop1,pop2]<-mean(df$Fst, na.rm=T)
    }
    diag(pairch)<-0
    pairch$pop<-rownames(pairch)
    dfm<-melt(pairch,na.rm=T, id.vars='pop')
    
    #NA to diagonal
    dfm$value[dfm$value==0]<-NA
    dfm$pop<-factor(dfm$pop, levels=pops)
    dfm$value<-round(dfm$value, 4)
    dfm$chr<-j
    Fst<-rbind(Fst, dfm)
    
}
Fst$id<-paste0(Fst$pop," vs.",Fst$variable)
Fst<-Fst[!is.na(Fst$value),]
ggplot(Fst, aes(x=chr, y=value,color=id))+
    geom_point()+
    geom_path(stat="identity")+
    theme_minimal()+ylab("Fst")+
    scale_x_continuous(breaks=1:26, labels = 1:26)+
    theme(legend.title = element_blank(), panel.grid.minor.x = element_blank())
ggsave("../Output/SFS/TB_Fst_byChromosome_dotplot.png", width = 13, height=6.5, dpi=150)

TB mean Fst per chromosome


2.3 Sitka Sound

2.3.1 Pairwise Fst along the genome

2.3.2 Pairwise Fst along each chromosome

## Plot Fst values along each chromosome
fst$chr<-factor(fst$chr, levels=paste0("chr",1:26))
fstss<-fst
plots<-list()
compare<-paste0(unique(fstss$pop))
for (i in 1:3){ 
    fs<-gsub("vs.","",compare[i])
    pops <- unlist(strsplit(fs, "\\."))
    maxy<-max(fstss$Fst[fstss$pop==compare[i]])
    # Fst with actual line to highlight the differences
    plots[[i]] <- ggplot(fstss[fstss$pop==compare[i],], aes(x =midPos, y =Fst )) + 
        geom_point(size = 1, color = gry,alpha = 0.4, shape = 1)+
        theme_minimal()+ylim(0,maxy+0.02)+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color=blu, size=0.2)+
        facet_wrap(~chr, ncol = 9)
}

{png(paste0("Output/SFS/SS_Fst_maf00_chr.png"), height = 4, width = 18, res=150, units = "in")  
grid.arrange(plots[[1]], plots[[2]], plots[[3]], ncol=3)  
dev.off()  }

2.3.3 Pairwise Fst matrix

## Continued from the above
pops<-c("SS96","SS06","SS17")
comb<-t(combn(pops,2))

## Plot average fst in a heatmap
compare<-unique(fst$pop)
pairfst<-data.frame(matrix(ncol=3, nrow=3), row.names=pops)
colnames(pairfst)<-pops
for (i in 1:3){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-fst[fst$pop==compare[i],]
    pairfst[pop1,pop2]<-mean(df$Fst, na.rm=T)
}
write.csv(pairfst,"../Output/SFS/SS_pairwiseFst_matrix.csv")

pairfst<-read.csv("../Output/SFS/SS_pairwiseFst_matrix.csv", row.names = 1)
df<-pairfst
diag(df)<-0
df$pop<-rownames(df)
dfm<-melt(df,na.rm=T, id.vars='pop')
#NA to diagonal
dfm$value[dfm$value==0]<-NA
dfm$pop<-factor(dfm$pop, levels=pops)
dfm$value<-round(dfm$value, 4)
ggplot(data = dfm, aes(pop, variable, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FF"), limits=c(0, (max(dfm$value, na.rm=T)+0.005)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(pop, variable, label = value), color = "black", size = 5)
ggsave(paste0("../Output/SFS/pairwiseFst_SS.png"), width = 5, height = 5, dpi=150)

# Plot Fst in a bar plot ordered and colored in the same way as Fst/Pi shuffle results (Shuffling_pi.fst.tehat.Rmd)
fsts<-dfm[!is.na(dfm$value),]
fsts$comp<-paste0(fsts$pop,"_",fsts$variable)

#set the colors
#div1<-diverging_hcl(6, palette="Blue-Red")
#div2<-rev(div1)
#names(div2)<-c("PWS96_PWS07","PWS07_PWS17","PWS91_PWS96", "PWS91_PWS07", "PWS91_PWS17","PWS96_PWS17")
fsts<-fsts[order(fsts$value, decreasing = T),]
fsts$comp<-factor(fsts$comp, levels=paste0(unique(fsts$comp)))

ggplot(fsts, aes(x=comp, y=value, fill=comp))+
    geom_bar(stat="identity")+
    scale_fill_manual(values = div1)+
    xlab('')+ylab('Fst')+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())
ggsave("../Output/Fst/TB_PairwiseFst_ordered.png", width = 3.4, height = 2.8, dpi=300 )

#Fst over time
fsts2<-fsts[fsts$comp %in% c("SS96_SS06","SS06_SS17"),]
fsts2$time<-1
fsts2$time[fsts2$comp=="SS96_SS06"]<-2
fsts2$time[fsts2$comp=="SS06_SS17"]<-3
fsts2<-fsts2[order(fsts2$time),]
ggplot(fsts2, aes(x=time, y=value))+
    geom_point(size=3, color="steelblue")+
    geom_path( aes(x=time, y=value),color="steelblue")+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))
ggsave("../Output/Fst/Fst_overTime_SS.png", width = 3.5, height = 2.8, dpi=300 )

fsts$series<-"1991-2007, 1991-2017"
fsts$series[fsts$comp =="SS96_SS17"]<-"1996-2017"
fsts$time<-1
fsts$time[fsts$variable=="SS17"]<-3
fsts$time[fsts$variable=="SS06"]<-2
#source("../Rscripts/BaseScripts.R")
fsts<-fsts[order(fsts$time),]
ggplot(fsts, aes(x=time, y=value, color=series))+
    geom_point(size=3)+
    geom_path()+
    scale_color_manual(values=cols)+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "~2007","~2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_SS_allComparison.png", width = 6, height = 2.8, dpi=300 )


# plot all 3 pops together

fsts2$pop<-"SS"

fstPST<-rbind(fstPT, fsts2)

ggplot(fstPST, aes(x=time, y=value, color=pop))+
    geom_point(size=3)+
    geom_path( aes(x=time, y=value))+
    scale_color_manual(values=cols[c(2,1,3)])+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_3Pops.png", width = 5, height = 2.8, dpi=300 )

2.3.4 Mean pairsie Fst per chromosome

# Plot mean Fst of each chromosomes
Fst<-data.frame()
for (j in 1:26){
    fst.ch<-fst[fst$ch==j,]
    pairch<-data.frame(matrix(ncol=3, nrow=3), row.names=pops)
    colnames(pairch)<-pops
    for (i in 1:3){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        df<-fst.ch[fst.ch$pop==compare[i],]
        pairch[pop1,pop2]<-mean(df$Fst, na.rm=T)
    }
    diag(pairch)<-0
    pairch$pop<-rownames(pairch)
    dfm<-melt(pairch,na.rm=T, id.vars='pop')
    
    #NA to diagonal
    dfm$value[dfm$value==0]<-NA
    dfm$pop<-factor(dfm$pop, levels=pops)
    dfm$value<-round(dfm$value, 4)
    dfm$chr<-j
    Fst<-rbind(Fst, dfm)
    
}
Fst$id<-paste0(Fst$pop," vs.",Fst$variable)
Fst<-Fst[!is.na(Fst$value),]
ggplot(Fst, aes(x=chr, y=value,color=id))+
    geom_point()+
    geom_path(stat="identity")+
    theme_minimal()+ylab("Fst")+
    scale_x_continuous(breaks=1:26, labels = 1:26)+
    theme(legend.title = element_blank(), panel.grid.minor.x = element_blank())
ggsave("../Output/SFS/SS_Fst_byChromosome_dotplot.png", width = 8, height=4.5, dpi=150)

2.4 2017 Populations

2.4.1 Pairiwse Fst along the genome

popsn<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-unique(popsn$Population.Year)
y17<-pops[grep("17",pops)]

comb<-combn(y17, 2)
comb<-t(comb)

#Year2017
fst17<-data.frame()
for (i in 1: nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_folded_",pop1,"_",pop2,"_50kWindow_maf00"))
    conames<-colnames(df)[2:4]
    colnames(df)[4]<-"Fst"
    colnames(df)[1:3]<-conames
    df$pop<-paste0(pop1,".vs.",pop2)
    df$ch=as.integer(gsub("chr","", df$chr))
    df<-df[order(df$ch),]
    df$loc<-1:nrow(df)
    fst17<-rbind(fst17, df)
}

write.csv(fst17,"../Output/SFS/Fst_window_year2017_allpops.csv")

fst17$ch<-as.integer(gsub("chr","",fst17$chr))
fst17<-fst17[order(fst17$ch, fst17$midPos),]
fst17$chr<-factor(fst17$chr, levels=paste0("chr",1:26))

pairs<-unique(fst17$pop)
plots<-list()
for (i in 1:length(pairs)){ 
    fs<-gsub(".vs","",pairs[i])
    pops <- unlist(strsplit(fs, "\\."))
    # Fst with actual line to highlight the differences
    df<-fst17[fst17$pop==pairs[i],]
    plots[[i]] <- ggplot(df, aes(x =midPos, y = Fst)) + 
        geom_point(size = 1, color = "gray",alpha = 0.4, shape = 1)+
        theme_minimal()+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color="steelblue", size=0.2)+
        facet_wrap(~chr, ncol = 9)
}

#Same y-axis
plots2<-list()
#TB ylim=0.8
#nonTB 0.6
for (i in 1:length(pairs)){ 
    fs<-gsub(".vs","",pairs[i])
    pops <- unlist(strsplit(fs, "\\."))
    # Fst with actual line to highlight the differences
    df<-fst17[fst17$pop==pairs[i],]
    if (i %in% c(4,8,11,13,15)) ymax=0.8
    else ymax=0.6
    plots2[[i]] <- ggplot(df, aes(x =midPos, y = Fst)) + 
        geom_point(size = 1, color = "gray",alpha = 0.4, shape = 1)+
        theme_minimal()+ylim(0,ymax)+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color="steelblue", size=0.2)+
        facet_wrap(~chr, ncol = 9)
}
{png(paste0("../Output/SFS/Year2017_Fst1.png"), height = 8, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots[1:6], ncol=3))
dev.off()}

{png(paste0("../Output/SFS/Year2017_Fst2.png"), height = 12, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots[7:15], ncol=3))
dev.off()}

#plot non-TB
{png(paste0("../Output/SFS/Year2017_Fst_sameYaxis.png"), height = 16, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots2[c(1,2,3,5,6,7,9,10,12,14)], ncol=3))
dev.off()}

{png(paste0("../Output/SFS/Year2017_Fst_sameYaxis2_TB.png"), height = 12, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots2[c(4,8,11,13,15)], ncol=3))
dev.off()}

contrast without TB

Contrast against TB pop

2.4.2 Paiwise Fst matrix

#Plot pairwise Fst values
bcxca <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.CA17"]),4)
bcxpw <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.PWS17"]),4)
caxpw <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.PWS17"]),4)
bcxwa <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.WA17"]),4)
caxwa <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.WA17"]),4)
bcxss <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.SS17"]),4)
bcxtb <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.TB17"]),4)
ssxtb <- round(mean(fst17$Fst[fst17$pop=="SS17.vs.TB17"]),4)
caxss <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.SS17"]),4)
pwxss <- round(mean(fst17$Fst[fst17$pop=="PWS17.vs.SS17"]),4)
caxtb <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.TB17"]),4)
pwxtb <- round(mean(fst17$Fst[fst17$pop=="PWS17.vs.TB17"]),4)
pwxwa <- round(mean(fst17$Fst[fst17$pop=="PWS17.vs.WA17"]),4)
ssxwa <- round(mean(fst17$Fst[fst17$pop=="SS17.vs.WA17"]),4)
tbxwa <- round(mean(fst17$Fst[fst17$pop=="TB17.vs.WA17"]),4)

fst_vec <- c(0,pwxtb,ssxtb,bcxtb,tbxwa,caxtb,
             pwxtb,0,pwxss,bcxpw,pwxwa,caxpw,
             ssxtb,pwxss,0,bcxss,ssxwa,caxss,
             bcxtb,bcxpw,bcxss,0,bcxwa,bcxca,
             tbxwa,pwxwa,ssxwa,bcxwa,0,caxwa,
             caxtb,caxpw,caxss,bcxca,caxwa,0)

fst_mat = matrix(fst_vec, nrow = 6, ncol = 6)
colnames(fst_mat) <- c("TB17","PWS17","SS17","BC17","WA17","CA17")
rownames(fst_mat) <- c("TB17","PWS17","SS17","BC17","WA17","CA17")

fst_mat[lower.tri(fst_mat, diag = F)]<-NA
write.csv(fst_mat, "../Output/SFS/Fst_matrix_2017_all.csv")

# Melt the correlation matrix
melted_cormat <- melt(fst_mat, na.rm = TRUE)
melted_cormat[melted_cormat==0]<-NA
# Heatmap
melted_cormat$color<-"a"
melted_cormat$color[melted_cormat$value>=0.1]<-"b"

ggplot(data = melted_cormat, aes(Var2, Var1, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "blue"), limits=c(0, (max(melted_cormat$value, na.rm=T)+0.005)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(Var2, Var1, label = value, color=color),  size = 5)+
    scale_color_manual(values=c("black", "white"), guide='none')
ggsave("../Output/SFS/Fst_matrix_2017_all.png", height = 6, width = 6, dpi=150)

2.5 Fst change over time between PWS/SS/TB

comb<-data.frame(a=c("PWS91","PWS96","PWS07","PWS17","PWS96","PWS07","PWS17","SS96","SS06","SS17"),b=c("TB91","TB96","TB06","TB17","SS96","SS06","SS17","TB96","TB06","TB17")) 

fsts<-data.frame()
for (i in 1: nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_folded_",pop1,"_",pop2,"_50kWindow_maf00"))
    conames<-colnames(df)[2:4]
    colnames(df)[4]<-"Fst"
    colnames(df)[1:3]<-conames
    df$pop<-paste0(pop1,".vs.",pop2)
    df$ch=as.integer(gsub("chr","", df$chr))
    df<-df[order(df$ch),]
    df$loc<-1:nrow(df)
    fsts<-rbind(fsts, df)
}
write.csv(fsts,"../Output/SFS/Fst_betweenPop.csv")

re<-aggregate(fsts$Fst, by=list(fsts$pop), mean, na.rm=T)
compa<-strsplit(re$Group.1, split=".vs.")
re$pop1<-lapply(compa, "[[", 1)
re$pop2<-lapply(compa, "[[", 2)
re$year <- as.numeric(str_extract(re$pop1, "[0-9]+"))
re$year[re$year==7|re$year==6]<-2006
re$year[re$year==91]<-1991
re$year[re$year==96]<-1996
re$year[re$year==17]<-2017
re$pop1<-str_extract(re$pop1, "[aA-zZ]+")
re$pop2<-str_extract(re$pop2, "[aA-zZ]+")
re$pops<-paste0(re$pop1,"-",re$pop2)

ggplot(re, aes(x=year, y=x, color=pops, group=pops))+
    geom_point(position=position_dodge(width = 1), size=3)+
    geom_line(position=position_dodge(width = 1))+
    ylab("Fst")+xlab("Year")+
    theme_classic()+theme(legend.title = element_blank())+
    scale_color_manual(values=cols[c(1,5,4)])
ggsave("../Output/SFS/Fst_shift_overYears_3pops.png", width = 5, height = 3, dpi=300)



3 Use Pixy to calculate pi

3.1 Steps

  1. Create all sites (invariant) vcf files
    (see invariantVCF_PWS91.sh)
  1. Reformat the sample file (’_’ was replaced by ‘.’ in the process of making vcf files)
pops<-c("PWS91","PWS96","PWS07","PWS17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/pixy/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}

pops<-c("TB91","TB96","TB06","TB17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/pixy/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"/" ,pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}

pops<-c("SS96","SS06","SS17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/popinfo/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"/" ,pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}
pops<-c("CA17","BC17","WA17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/popinfo/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"/" ,pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}
  1. Run Pixy (example: PWS91 Chr1)
#index the vcf.gz file
tabix PWS91_ch1.vcf.gz

# Run Pixy 
#first activate the conda env (py38) -runs on older Python (<=3.8)
conda activate py38
cd ~/Projects/PacHerring/Data/pixy
pixy --stats pi --vcf PWS91_ch1.vcf.gz --populations pws91pop.txt --window_size 10000 --n_core 8 --output_prefix PWS91_ch1

conda deactivate
  1. Summarize the output from Pixy for PWS91 Chr1
pipi<-read.table("../Data/pixy/PWS91/PWS91_ch1_pi.txt", header=T)
ggplot(pipi, aes(x=window_pos_1, y=avg_pi))+
    geom_line(color=blu)+xlab('')+ylab(expression("mean "*pi))
ggsave("../Output/SFS/pixy_pi_pws91_ch1_line.png", width = 6, height = 3.5, dpi=300)

ggplot(pipi, aes(x=window_pos_1, y=avg_pi))+
    geom_point(size=0.3, color="gray20")

mean(pipi$avg_pi)
# 0.00278471

#weighted mean
pipi$pi_sum<-pipi$avg_pi*pipi$no_sites
sum(pipi$pi_sum)/sum(pipi$no_sites)
# 0.002775464

3.2 Compare π estimated from ANGSD vs. Pixy

#Compare with the pi estimated from ANGSD SFS 
theta<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/PWS91_50kwin_10kstep.pestPG'))
theta$pi<-theta$tP/theta$nSites
mean(theta$pi[theta$Chr=="chr1"])
#0.003826297

#chr1 comparison
ch1<-pipi[,c("chromosome", "avg_pi")]
ch1$method<-"Pixy"
theta2<-theta[,c("Chr","pi")]
theta2$method<-"ANGSD"
colnames(ch1)[1:2]<-c("Chr","pi")
ch1<-rbind(ch1,theta2)


ggplot(ch1, aes(x=method, y=pi))+
    geom_boxplot(aes(middle=mean(pi), color=method),outlier.alpha = 0.2)+
    theme_classic()+xlab('')+ylab(expression(pi))+
    scale_color_manual(values=c("#1f78b4","#fb9a99"), guide='none')
ggsave("../Output/SFS/Pi_comparison_pixy.vs.angsd.pws91.ch1.png", width=4, height=4,dpi=200 )

3.2.1 Run Pixy for all chromosomes for PWS

#index vcf files for all chromosomes
for f in *.vcf.gz; do
filename=$(basename $f)
tabix $f 
done
#create a script to run pixy
for (j in 1: length(pops)){
    sink(paste0("../Data/pixy/runpixy_", pops[j],".sh"))
    cat("#!/bin/bash\n\n")
    for (i in 1:26){
        cat(paste0("pixy --stats pi --vcf ",pops[j],"_ch",i,".vcf.gz --populations ",pops[j],"pop.txt --window_size 10000 --n_core 8 --output_prefix ",pops[j], "_ch",i, "\n"))
    }
    sink(NULL)
}

3.2.2 Plot the outputs from Pixy for all PWS groups

#read the output file for PWS:
pops<-c("PWS91","PWS96","PWS07","PWS17")

for (p in 1 : length(pops)){
    pixy<-data.frame()
    for (i in 1:26){
        df<-read.table(paste0("../Data/pixy/",pops[p],"/",pops[p],"_ch",i,"_pi.txt"), header=T)
        df$method<-"Pixy"
        df$WinCenter<-df$window_pos_2-5000
        df<-df[,c("chromosome","WinCenter","avg_pi","method")]
        colnames(df)[c(1,3)]<-c("Chr","pi")
        pixy<-rbind(pixy, df)
    }
    write.csv(pixy, paste0("../Output/Pi/",pops[p], "_Pi_pixy_per50kWindow.csv"))
    
    #Compare with the pi estimated from ANGSD SFS 
    theta<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/',pops[p],'_50kwin_10kstep.pestPG'))
    theta$pi<-theta$tP/theta$nSites
    theta$method<-"ANGSD"
    pi<-rbind(pixy, theta[,c("Chr","WinCenter","pi","method")])

    pi$Chr<-factor(pi$Chr, levels=paste0("chr",1:26))
    ggplot(pi, aes(x=Chr, y=pi, color=method))+
        geom_boxplot(aes(middle=mean(pi)),outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+theme(axis.text.x = element_text(angle=45, hjust =1))+
        xlab("")+ylab(expression(pi))+ggtitle(pops[p])+
        scale_color_manual(values=c("#1f78b4","#fb9a99"))
    ggsave(paste0("../Output/Pi/Pi_comparison_pixy.vs.angsd.",pops[p], ".png"), width = 10, height = 5, dpi=100)
    
    # genome-wide mean pi comparison
    means <- aggregate(pi ~  method, pi, mean)
    
    ggplot(pi, aes(x=method, y=pi))+
        geom_boxplot(aes(color=method), outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+ ggtitle(pops[p])+
        geom_point(stat = "summary", fun = "mean", color="gray40")+
         xlab("")+ylab(expression(pi))+
        scale_color_manual(values=c("#1f78b4","#fb9a99"), guide='none')+
        geom_text(data = means, aes(label = round(pi, digits=5), y = pi + 0.02), color="gray40")
    ggsave(paste0("../Output/Pi/Pi_comparison_pixy.vs.angsd_mean_",pops[p],".png"), width = 3, height = 3, dpi=200)
}

PWS91

PWS07

PWS17

  • Pixy estimates have more variability
  • Pixy esitmates are slightly lower than ANSGD estiamtes
# Assess the differences between ANGSD and Pixy
pops<-c("PWS91","PWS96","PWS07","PWS17")
diff<-data.frame(pop=pops)
for (p in 1 : length(pops)){
    pixy<-data.frame()
    for (i in 1:26){
        df<-read.table(paste0("../Data/pixy/",pops[p],"/",pops[p],"_ch",i,"_pi.txt"), header=T)
        df$method<-"Pixy"
        df$WinCenter<-df$window_pos_2-5000
        df<-df[,c("chromosome","WinCenter","avg_pi","method")]
        colnames(df)[c(1,3)]<-c("Chr","pi")
        pixy<-rbind(pixy, df)
    }
    #mean.pixy<-aggregate(pixy$pi, by=list(pixy$Chr), mean, na.rm=T)
    
    #Pi estimated from ANGSD SFS 
    theta<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/',pops[p],'_50kwin_10kstep.pestPG'))
    theta$pi<-theta$tP/theta$nSites
    theta$method<-"ANGSD"
    pi<-rbind(pixy, theta[,c("Chr","WinCenter","pi","method")])

    means<-aggregate(pi$pi, by=list(pi$method), mean, na.rm=T)
    
    #differences in pi estimates
    
    diff$prop.difference[p]<-means$x[means$Group.1=="ANGSD"]/means$x[means$Group.1=="Pixy"]
}


knitr::kable(diff)

3.2.3 Compare across years -PWS

pops<-c("PWS91","PWS96","PWS07","PWS17")
Pi<-data.frame()
for (i in 1:length(pops)){
    pi<-read.csv(paste0("../Output/Pi/",pops[i], "_Pi_pixy_per50kWindow.csv"), row.names =1 )
    pi$Chr<-factor(pi$Chr, levels=paste0("chr",1:26))
    pi$pop<-pops[i]
    Pi<-rbind(Pi,pi)
}

Pi$pop<-factor(Pi$pop, levels=pops)

means <- aggregate(pi ~ pop,Pi, mean)
ggplot(Pi, aes(x=pop, y=pi, color=pop))+
        geom_boxplot(aes(color=pop), outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+ ggtitle("PWS")+
        geom_point(stat = "summary", fun = "mean", color="gray40")+
         xlab("")+ylab(expression(pi))+
        geom_text(data = means, aes(label = round(pi, digits=5), y = pi + 0.02), color="gray40")
ggsave(paste0("../Output/Pi/Pi_pixy_mean.",pops[i],".png"), width = 4.5, height = 3, dpi=200)

#read the output file for each pops:
pops<-c("TB91","TB96","TB06","TB17")

for (p in 1 : length(pops)){
    pixy<-data.frame()
    for (i in 1:26){
        df<-read.table(paste0("../Data/pixy/",pops[p],"/",pops[p],"_ch",i,"_pi.txt"), header=T)
        df$method<-"Pixy"
        df$WinCenter<-df$window_pos_2-5000
        df<-df[,c("chromosome","WinCenter","avg_pi","method")]
        colnames(df)[c(1,3)]<-c("Chr","pi")
        pixy<-rbind(pixy, df)
    }
    write.csv(pixy, paste0("../Output/Pi/",pops[p], "_Pi_pixy_per50kWindow.csv"))
}

Pi<-data.frame()
for (i in 1:length(pops)){
    pi<-read.csv(paste0("../Output/Pi/",pops[i], "_Pi_pixy_per50kWindow.csv"), row.names =1 )

    pi$Chr<-factor(pi$Chr, levels=paste0("chr",1:26))
    ggplot(pi, aes(x=Chr, y=pi))+
        geom_boxplot(aes(middle=mean(pi)),outlier.alpha = 0.2, outlier.size = 0.6,color="#1f78b4")+
        theme_classic()+theme(axis.text.x = element_text(angle=45, hjust =1))+
        xlab("")+ylab(expression(pi))+ggtitle(pops[i])
    ggsave(paste0("../Output/Pi/Pi_pixy.perChrom.",pops[i], ".png"), width = 8.5, height = 5, dpi=300)
    
    pi$pop<-pops[i]
    Pi<-rbind(Pi,pi)
}

Pi$pop<-factor(Pi$pop, levels=pops)
means <- aggregate(pi ~ pop,Pi, mean)
ggplot(Pi, aes(x=pop, y=pi, color=pop))+
        geom_boxplot(aes(color=pop), outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+ ggtitle("TB")+
        geom_point(stat = "summary", fun = "mean", color="gray40")+
         xlab("")+ylab(expression(pi))+
        geom_text(data = means, aes(label = round(pi, digits=5), y = pi + 0.02), color="gray40")
ggsave(paste0("../Output/Pi/Pi_pixy_mean.TB.png"), width = 4.5, height = 3, dpi=200)

pops<-c("PWS91","PWS96","PWS07","PWS17","TB91","TB96","TB06","TB17","SS96","SS06","SS17")
year<-c(1991,1996,2007,2017,1991,1996,2006,2017,1996,2006,2017)
meanPi<-data.frame(pop.yr=pops, year=year)
for (i in 1:length(pops)){
    df<-read.csv(paste0("../Output/Pi/",pops[i], "_Pi_pixy_per50kWindow.csv"), row.names =1 )
    meanPi$mean[i]<-mean(df$pi, na.rm=T)
    meanPi$pop[i]<-gsub("\\d.+","",pops[i])
}


ggplot(meanPi, aes(x=year, y=mean, color=pop))+
    geom_point(size=3)+
    geom_line()+
    xlab("")+ylab(paste0("Mean ",expression(pi)))+
    theme_linedraw()+
    scale_color_manual(values=cols[c(2,1,5)])
ggsave("../Output/Pi/Pi_overYears.PWS.TB.SS.png", width = 6, height = 4, dpi=300)

3.2.4 Bootstrap pi values to get 95% CI


# average theta values across sites

#############
# Parameters
#############
# number of chromosomes in each sample
#nchrCan40 <- 42 # sample size in # chromosomes
#nchrCan14 <- 48
#nchrLof07 <- 44
#nchrLof11 <- 48
#nchrLof14 <- 44

nboot <- 1000

nchr=26

####################
# load functions
require(data.table)
require(boot) # for bootstrap CIs


# For Tajima's D calcs. After https://github.com/ANGSD/angsd/blob/master/misc/stats.cpp
a1f <- function(nsam) return(sum(1/seq(1, nsam-1)))
a2f <- function(nsam) return(sum(1/(seq(1, nsam-1)*seq(1, nsam-1))))
b1f <- function(nsam) return((nsam + 1)/(3*(nsam-1)))
b2f <- function(nsam) return((2*(nsam*nsam + nsam + 3))/(9*nsam*(nsam - 1)))
c1f <- function(a1, b1) return(b1 - (1/a1))
c2f <- function(nsam, a1, a2, b2) return(b2 - ((nsam + 2)/(a1*nsam)) + (a2/(a1 * a1)))
e1f <- function(a1, c1) return(c1/a1)
e2f <- function(a1, a2, c2) return(c2/((a1*a1) + a2))

# Tajima's D calculation
# nsam: sample size
# thetaW: Watterson's theta (# segregating sites / a1)
# sumk: theta pi (average number of SNPs in pairwise comparisons)
# after https://github.com/ANGSD/angsd/blob/master/misc/stats.cpp
tajd <- function(nsam, thetaW, sumk){
    a1 <- a1f(nsam)
    segsites <- thetaW * a1
    if(segsites == 0) return(0)
    a2 <- a2f(nsam)
    b1 <- b1f(nsam)
    b2 <- b2f(nsam)
    c1 <- c1f(a1, b1)
    c2 <- c2f(nsam, a1, a2, b2)
    e1 <- e1f(a1, c1)
    e2 <- e2f(a1, a2, c2)
    res <- (sumk - (thetaW))/sqrt((e1*segsites) + ((e2*segsites)*(segsites-1)))
    return(res)
}

# calc thetas
calcthetas <- function(dat, nchr, nloci){
    # calc ave theta
    thetas <- as.numeric(dat[, .(tW = sum(exp(Watterson)/nloci, na.rm = TRUE), tP = sum(exp(Pairwise)/nloci, na.rm = TRUE))])

    # calculate Tajima's D
    thetas[3] <- tajd(nchr, thetas[1], thetas[2])
    
    #return
    names(thetas) <- c('tW', 'tP', 'tD')
    return(thetas)
}

# calculate stats from specified LGs for block bootstrapping across LGs
thetablock <- function(lgs, indices, alldata, nchr, regs){
    # make bootstrapped dataset
    mydata <- do.call("rbind", lapply(indices, function(n) subset(alldata, Chromo==lgs[n])))
    
    # calculate number of callable loci, given the LGs in this bootstrapped sample
    nloci <- regs[Chromo %in% lgs, .(len = Pos2 - Pos1 + 1), by = .(Chromo, Pos1)][, sum(len)] # sum of bp in the callable region
    
    # calc thetas
    thetas <- calcthetas(mydata, nchr, nloci)
    
    # return
    return(thetas)
}

#using window based angsd file (use preknown loci in 50000 windows)
thetablock2 <- function(lgs, indices, alldata, nchr, regs){
    # make bootstrapped dataset
    mydata <- do.call("rbind", lapply(indices, function(n) subset(alldata, Chromo==lgs[n])))
    
    # calculate number of callable loci, given the LGs in this bootstrapped sample
    #nloci <- regs[Chromo %in% lgs, .(len = Pos2 - Pos1 + 1), by = .(Chromo, Pos1)][, sum(len)] # sum of bp in the callable region

    nloci <- alldata[Chromo %in% lgs,sum(nSites)] # sum of bp in the callable region
    
    # calc thetas
    thetas <- calcthetas(mydata, nchr, nloci)
    
    # return
    return(thetas)
}


######################
# Load data
######################
alldata<-dat
# load all loci theta calcs
dat<-fread('../Data/new_vcf/angsd/fromVCF/BC17_maf00.thetas50kWindow.gz.pestPG')
setnames(dat, 'Chr', 'Chromo')

datCan40 <- fread('analysis/thetas.Can_40.pestPG.gz')
datCan14 <- fread('analysis/thetas.Can_14.pestPG.gz')
datLof07 <- fread('analysis/thetas.Lof_07.pestPG.gz')
datLof11 <- fread('analysis/thetas.Lof_11.pestPG.gz')
datLof14 <- fread('analysis/thetas.Lof_14.pestPG.gz')

# gatk loci
datCan40gatk <- fread('analysis/thetas.Can_40.gatk.pestPG.gz')
datCan14gatk <- fread('analysis/thetas.Can_14.gatk.pestPG.gz')
datLof07gatk <- fread('analysis/thetas.Lof_07.gatk.pestPG.gz')
datLof11gatk <- fread('analysis/thetas.Lof_11.gatk.pestPG.gz')
datLof14gatk <- fread('analysis/thetas.Lof_14.gatk.pestPG.gz')

# fix name
setnames(datCan40, '#Chromo', 'Chromo')
setnames(datCan14, '#Chromo', 'Chromo')
setnames(datLof07, '#Chromo', 'Chromo')
setnames(datLof11, '#Chromo', 'Chromo')
setnames(datLof14, '#Chromo', 'Chromo')

setnames(datCan40gatk, '#Chromo', 'Chromo')
setnames(datCan14gatk, '#Chromo', 'Chromo')
setnames(datLof07gatk, '#Chromo', 'Chromo')
setnames(datLof11gatk, '#Chromo', 'Chromo')
setnames(datLof14gatk, '#Chromo', 'Chromo')

windownames<-colnames(dat)[1]
colnames(dat)[1]<-"window"
## list of callable regions

dat$window<-gsub("\\(",'', dat$window)
dat$window<-gsub("\\)$",'', dat$window)
dat$window<-gsub("\\)",',', dat$window)
windows1<-str_split_fixed(dat$window,",",6) 
colnames(windows1)<-c('IndexStart', 'IndexStop','firstPos_withData','lastPos_withData','WinStart','WinStop')

dat<-cbind(windows1, dat)

regs<-dat[,c("Chromo","WinStart","WinStop")]
names(regs)<-c('Chromo', 'Pos1', 'Pos2')
#regs <- fread('data_2020.05.07/Callable_bases_gadmor2.bed')
#setnames(regs, c('Chromo', 'Pos1', 'Pos2'))
#
## list of no damage sites
#nodam <- fread('data_2020.05.07/GATK_filtered_SNP_no_dam2.tab')
#setnames(nodam, c('Chromo', 'Pos', 'REF', 'ALT'))
#
#
## remove unplaced
#datCan40 <- datCan40[grep('Unplaced', Chromo, invert = TRUE), ]
#datCan14 <- datCan14[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof07 <- datLof07[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof11 <- datLof11[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof14 <- datLof14[grep('Unplaced', Chromo, invert = TRUE), ]
#
#datCan40gatk <- datCan40gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datCan14gatk <- datCan14gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof07gatk <- datLof07gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof11gatk <- datLof11gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof14gatk <- datLof14gatk[grep('Unplaced', Chromo, invert = TRUE), ]

regs <- regs[Chromo != 'Unplaced', ]
nodam <- nodam[Chromo != 'Unplaced', ]

###################################################
# create table of loci trimmed to no damage sites
###################################################

datCan40gatknd <- merge(datCan40, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datCan14gatknd <- merge(datCan14, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datLof07gatknd <- merge(datLof07, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datLof11gatknd <- merge(datLof11, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datLof14gatknd <- merge(datLof14, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim


################################
# Run theta calculations
################################
#nloci <- regs[, .(len = Pos2 - Pos1 + 1), by = .(Chromo, Pos1)][, sum(len)] # sum of bp in the callable region

nloci<-dat$nSites

# all loci
calcthetas(dat, nchr, nloci)
calcthetas(datCan14, nchrCan14, nloci)
calcthetas(datLof07, nchrLof07, nloci)
calcthetas(datLof11, nchrLof11, nloci)
calcthetas(datLof14, nchrLof14, nloci)

# gatk loci
calcthetas(datCan40gatk, nchrCan40, nloci)
calcthetas(datCan14gatk, nchrCan14, nloci)
calcthetas(datLof07gatk, nchrLof07, nloci)
calcthetas(datLof11gatk, nchrLof11, nloci)
calcthetas(datLof14gatk, nchrLof14, nloci)

# gatk no damage loci
calcthetas(datCan40gatknd, nchrCan40, nloci)
calcthetas(datCan14gatknd, nchrCan14, nloci)
calcthetas(datLof07gatknd, nchrLof07, nloci)
calcthetas(datLof11gatknd, nchrLof11, nloci)
calcthetas(datLof14gatknd, nchrLof14, nloci)




# block bootstrapping across LGs

#lgs <- datCan40[, sort(unique(Chromo))]
datlist <- list(datCan40, datCan14, datLof07, datLof11, datLof14, 
                datCan40gatk, datCan14gatk, datLof07gatk, datLof11gatk, datLof14gatk,
                datCan40gatknd, datCan14gatknd, datLof07gatknd, datLof11gatknd, datLof14gatknd)
names(datlist) <- c('Can40 all loci', 'Can14 all loci', 'Lof07 all loci', 'Lof11 all loci', 'Lof14 all loci', 
                    'Can40 gatk loci', 'Can14 gatk loci', 'Lof07 gatk loci', 'Lof11 gatk loci', 'Lof14 gatk loci',
                    'Can40 gatk no dam loci', 'Can14 gatk no dam loci', 'Lof07 gatk no dam loci', 'Lof11 gatk no dam loci', 
                    'Lof14 gatk no dam loci')
nchrlist <- list(nchrCan40, nchrCan14, nchrLof07, nchrLof11, nchrLof14, nchrCan40, nchrCan14, nchrLof07, nchrLof11, nchrLof14, nchrCan40, nchrCan14, nchrLof07, nchrLof11, nchrLof14)

thetabootout <- data.frame(type = names(datlist), tW = NA, tWl95 = NA, tWu95 = NA, tP = NA, tPl95 = NA, tPu95 = NA, tD = NA, tDl95 = NA, tDu95 = NA)


#####

lgs <- dat[, sort(unique(Chromo))]

bootlg <- boot(lgs, thetablock2, nboot,  alldata = dat, nchr = nchr, regs = regs)


for(i in 1:length(datlist)){
    print(names(datlist)[i])
    
    
    bootlg <- boot(lgs, thetablock, nboot,  alldata = datlist[[i]], nchr = nchrlist[[i]], regs = regs)
    
    print(bootlg)
    ciW <- boot.ci(bootlg, type = c('perc'), index = 1)
    ciP <- boot.ci(bootlg, type = c('perc'), index = 2)
    ciD <- boot.ci(bootlg, type = c('perc'), index = 3)
    
    thetabootout$tW[i] <- bootlg$t0[1] # the point estimates
    thetabootout$tP[i] <- bootlg$t0[2]  
    thetabootout$tD[i] <- bootlg$t0[3]

    thetabootout$tWl95[i] <- ciW$percent[4] # the confidence intervals
    thetabootout$tWu95[i] <- ciW$percent[5]

    thetabootout$tPl95[i] <- ciP$percent[4]
    thetabootout$tPu95[i] <- ciP$percent[5]

    thetabootout$tDl95[i] <- ciD$percent[4]
    thetabootout$tDu95[i] <- ciD$percent[5]
}

# save
write.csv(thetabootout, file = 'analysis/thetas.boot.cis.csv')
LS0tCnRpdGxlOiAiU0ZTIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB0cnVlIAogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAgIHRoZW1lOiBsdW1lbgogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKCi0tLQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQp0b2MgPSB0YWJsZSBvZiBjb250ZW50cwoKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzb3VyY2UoIi4uL1JzY3JpcHRzL0Jhc2VTY3JpcHRzLlIiKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCgojIEVzdGlhbXRlIFNGUyB3aXRoIGFsbCBpbmRpdmlkdWFscyBhbmQgYWxsIHNpdGVzCgooZXN0aW1hdGVkIGJ5IGVhY2ggY2hyb21vc29tZSBhbmQgY29tYmluZSB0aGVtIGxhdGVyKSAoNS4yNi4yMn4pICAKClN0ZXAgMTogUnVuIFBXUzA3X3Nmc19zdGVwMS5zaCAoaW4gIi9EYXRhL1NsdXJ1bXNjcmlwdHMvU0ZTX2Zyb21CYW0vUFdTMDdfc2ZzX3N0ZXAxLnNoIikgZm9yIGVhY2ggcG9wdWxhdGlvbiAodGFrZXMgYSBsb25nIHRpbWUgdG8gY3JlYXRlIGEgc2FmIGZpbGUpICAKPGJyPgoKU3RlcCAyOiBSdW4gUFdTMDdfc2ZzX3N0ZXAyLnNoIHRvIGNyZWF0ZSB1bmZvbGRlZCBzZnMgZm9yIGVhY2ggY2hyb21vc29tZSAoQ2FuJ3QgcnVuIHRoZSB3aG9sZSBnZW5vbWUgZHVlIHRvIG1lbW9yeSBjb25zdHJhaW50cykgIAo8YnI+IAoKU3RlcCAyLjI6IFJ1biBQV1MwN19zZnNfc3RlcDJfZm9sZGVkLnNoIHRvIGNyZWF0ZSBmb2xkZWQgc2ZzIGZvciBlYWNoIGNocm9tb3NvbWUgICAKPGJyPgoKU3RlcCAzOiBSdW4gUiBzY3JpcHRzIHRvIGNvbWJpbmUgYWxsIHNmcyBpbnRvIDEKCmBgYHtiYXNoIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgYXQgRkFSTSwgcnVuIHRoZSBmb2xsb3dpbmcgc2NyaXB0cyB0byBjb21iaW5lIHNmcyBmaWxlcwptb2R1bGUgbG9hZCBSClIKc291cmNlKCJjb21iaW5lU0ZTZm9sZC5SIikgCnNvdXJjZSgiY29tYmluZVNGU3VuZm9sZC5SIikgCmNvbWJpbmVTRlN1bmZvbGQoIlBXUzA3IikgICAjIHRoaXMgd2lsbCBjcmVhdGUgYSAiUFdTMDdfdW5mb2xkZWQuc2ZzIiBpbiAvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL1NGUy9mcm9tQmFtLwpjb21iaW5lU0ZTZm9sZCgiUFdTMDciKSAgICMgdGhpcyB3aWxsIGNyZWF0ZSBhICJQV1MwN19mb2xkZWQuc2ZzIiBpbiAvaG9tZS9rdGlzdC9waC9kYXRhL2FuZ3NkL1NGUy9mcm9tQmFtL2ZvbGRlZC8KCiNFeGl0IFIgYnkgdHlwaW5nIApxdWl0KCkKYGBgCgogICAgCkxvY2FsbHksIHlvdSBjYW4gcnVuIGhlcmU6CmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY29tYmluZVNGU2ZvbGQ8LWZ1bmN0aW9uKHBvcCl7CiAgICBjaDE8LXNjYW4ocGFzdGUwKCJEYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS9mb2xkZWQvIixwb3AsIl9mb2xkZWRfY2hyMS5zZnMiKSkKICAgIHB3cy5zZnM8LWRhdGEuZnJhbWUoY2hyMT1jaDEpCiAgICBmb3IgKGkgaW4gMjoyNil7CiAgICAgICAgdmVjPC1zY2FuKHBhc3RlMCgiRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vZm9sZGVkLyIscG9wLCJfZm9sZGVkX2NociIsaSwiLnNmcyIpKQogICAgICAgIHB3cy5zZnNbLHBhc3RlMCgiY2hyIixpKV08LXZlYwogICAgfQogICAgcHdzLnNmcyRzdW08LXJvd1N1bXMocHdzLnNmcykKICAgIHNpbmsocGFzdGUwKCJEYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS9mb2xkZWQvIixwb3AsIl9mb2xkZWQuc2ZzIikpCiAgICBjYXQocHdzLnNmcyRzdW0pCiAgICBzaW5rKE5VTEwpCn0KCmNvbWJpbmVTRlN1bmZvbGQ8LWZ1bmN0aW9uKHBvcCl7CiAgICBjaDE8LXNjYW4ocGFzdGUwKCJEYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS91bmZvbGRlZC8iLHBvcCwiX3VuZm9sZGVkX2NocjEuc2ZzIikpCiAgICBwd3Muc2ZzPC1kYXRhLmZyYW1lKGNocjE9Y2gxKQogICAgZm9yIChpIGluIDI6MjYpewogICAgICAgIHZlYzwtc2NhbihwYXN0ZTAoIkRhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tQmFtL3VuZm9sZGVkLyIscG9wLCJfdW5mb2xkZWRfY2hyIixpLCIuc2ZzIikpCiAgICAgICAgcHdzLnNmc1sscGFzdGUwKCJjaHIiLGkpXTwtdmVjCiAgICB9CiAgICBwd3Muc2ZzJHN1bTwtcm93U3Vtcyhwd3Muc2ZzKQogICAgc2luayhwYXN0ZTAoIkRhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tQmFtL3VuZm9sZGVkLyIscG9wLCJfdW5mb2xkZWQuc2ZzIikpCiAgICBjYXQocHdzLnNmcyRzdW0pCiAgICBzaW5rKE5VTEwpCn0KCiNSdW4gd2l0aCB0aGUgJ3BvcCcgaWRlbnRpZmllcgpjb21iaW5lU0ZTdW5mb2xkKCJQV1MwNyIpCmNvbWJpbmVTRlNmb2xkKCJQV1MwNyIpCgpgYGAKClN0ZXAgNDogUnVuIFBXUzA3X3Nmc190aGV0YS5zaCB0byBjYWxjdWxhdGUgdGhldGEgYW5kIFRhamltYSdzIEQgZm9yIHVuZm9sZGVkLnNmcyAoRmF5ICYgV3UncyBIIHNob3VsZCBiZSB1c2VkIHdpdGggdW5mb2xkZWQgc2ZzKSAgCgpTdGVwIDQuMjogUnVuIFBXUzA3X3Nmc19zdGVwM19mb2xkZWQuc2ggdG8gY2FsY3VsYXRlIHRoZXRhIGFuZCBUYWppbWEncyBEIGZvciBmb2xkZWQuc2ZzIChUYWppbWEncyBEIHNob3VsZCBiZSB1c2VkIHdpdGggZm9sZGVkIHNmcykgIAoKIyMgU0ZTIGZyb20gYmFtIGZpbGVzIHsudGFic2V0fQoKIyMjIDFEU0ZTIFBXUwoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKcG9wczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQoKc2ZzMUQ8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgc2ZzIDwtIHNjYW4ocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS9jb21iaW5lZC8iLHBvcHNbaV0sIl91bmZvbGRlZC5zZnMiKSkKICAgIHNmczEgPC0gZGF0YS5mcmFtZShhYz1zZnMpCiAgICBzZnMxJGNvdW50PC0wOihucm93KHNmczEpLTEpCiAgICAjcmVtb3ZlIHRoZSBpbnZhcmlhYmxlIHNpdGVzCiAgICBzZnMxPC1zZnMxWy1jKDEsbnJvdyhzZnMxKSksXQogICAgc2ZzMSRwb3A8LXBvcHNbaV0KICAgIHNmczFEPC1yYmluZChzZnMxRCwgc2ZzMSkKfQogICAgCnNmczFEJHBvcDwtZmFjdG9yKHNmczFEJHBvcCwgbGV2ZWxzPXBvcHMpCmdncGxvdChkYXRhPXNmczFELCBhZXMoeD1jb3VudCwgeT1hYykpKwogICAgZmFjZXRfd3JhcCh+cG9wLCBuY29sPTQpKwogICAgICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3I9ImdyYXkiKSt4bGFiKCJGcmVxdWVuY3kgYmluIikrIHlsYWIoIk51bWJlciBvZiBhbGxlbGVzIikrCiAgICAgICAgdGhlbWVfY2xhc3NpYygpKwogICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9c2NhbGVzOjpjb21tYSkrCiAgICAgICAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICAgICAgY29sb3I9ImJsYWNrIiwgZmlsbD0iZ3JheTgwIiwgc2l6ZT0wLjUsIGxpbmV0eXBlPSJzb2xpZCIpKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvMURTRlNfZnJvbUJhbV9QV1MucG5nIiwgd2lkdGggPSAxMSwgaGVpZ2h0ID0gMi4yLCBkcGk9MzAwKQpgYGAKIVtdKC4uL091dHB1dC9TRlMvMURTRlNfZnJvbUJhbV9QV1MucG5nKQoKIyMjIFBpICjPgCkKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpCnRoZXRhPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIHRoZXRhMjwtcmVhZC5kZWxpbShwYXN0ZTAoJy4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tQmFtL3VuZm9sZGVkLycscG9wc1tpXSwnXzUwa3dpbl8xMGtzdGVwLnBlc3RQRycpKQogICAgdGhldGEyJHBpPC10aGV0YTIkdFAvdGhldGEyJG5TaXRlcwogICAgZGY8LXRoZXRhMlssYygiQ2hyIiwiV2luQ2VudGVyIiwicGkiLCJmYXloIiApXQogICAgZGYkcG9wPC1wb3BzW2ldICAgIAogICAgdGhldGE8LXJiaW5kKHRoZXRhLCBkZikKfQoKI21lYW4gcGkgYW5kIEZheSdzIEggIChmcm9tIHVuZm9sZGVkIFNGUykKdGhldGEkcG9wPC1mYWN0b3IodGhldGEkcG9wLCBsZXZlbHM9cG9wcykKCmdncGxvdCh0aGV0YSwgYWVzKHg9cG9wLCB5PXBpKSkrCiAgICBnZW9tX2JveHBsb3QocG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBjb2xvcj1ibHUsIG91dGxpZXIuYWxwaGEgPSAwLjYsb3V0bGllci5zaXplID0gMC43LHdpZHRoPTAuNikrCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpKwogICAgeWxhYihleHByZXNzaW9uKHBpKSkreGxhYigiIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41LDIuNSwzLjUpLCBjb2xvcj0iZ3JheSIsIHNpemU9MC41KQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvUGlfZXN0aW1hdGVzX1BXU19mcm9tQmFtLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMy41KQpgYGAKCiFbXSguLi9PdXRwdXQvU0ZTL1BpX2VzdGltYXRlc19QV1NfZnJvbUJhbS5wbmcpe3dpZHRoPTUwJX0gIAoKIyMjIEZheSdzIEgKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQpnZ3Bsb3QodGhldGEsIGFlcyh4PXBvcCwgeT1mYXloKSkrCiAgICBnZW9tX2JveHBsb3QocG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBjb2xvcj1ncmIsIG91dGxpZXIuYWxwaGEgPSAwLjYsb3V0bGllci5zaXplID0gMC43LHdpZHRoPTAuNikrCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpKwogICAgeWxhYigiRmF5J3MgSCIpK3hsYWIoIiIpKwogICAgdGhlbWVfYncoKSsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDEuNSwyLjUsMy41KSwgY29sb3I9ImdyYXkiLCBzaXplPTAuNSkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL0ZheUhfZXN0aW1hdGVzX1BXU19mcm9tQmFtLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMy41KQpgYGAKIVtdKC4uL091dHB1dC9TRlMvRmF5SF9lc3RpbWF0ZXNfUFdTX2Zyb21CYW0ucG5nKXt3aWR0aD01MCV9CgoKCiMjIyBUYWppbWEncyBECgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KCiNUYWppbWEncyBEIChmb2xkZWQgU0ZTKQp0aGV0YTwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOmxlbmd0aChwb3BzKSl7CiAgICB0aGV0YTI8LXJlYWQuZGVsaW0ocGFzdGUwKCcuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS9mb2xkZWQvJyxwb3BzW2ldLCdfNTBrd2luXzEwa3N0ZXAucGVzdFBHJykpCiAgICBkZjwtdGhldGEyWyxjKCJDaHIiLCJXaW5DZW50ZXIiLCJUYWppbWEiICldCiAgICBkZiRwb3A8LXBvcHNbaV0gICAgCiAgICB0aGV0YTwtcmJpbmQodGhldGEsIGRmKQp9Cgp0aGV0YSRwb3A8LWZhY3Rvcih0aGV0YSRwb3AsIGxldmVscz1wb3BzKQpnZ3Bsb3QodGhldGEsIGFlcyh4PXBvcCwgeT1UYWppbWEpKSsKICAgIGdlb21fYm94cGxvdChwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIGNvbG9yPW9yZywgb3V0bGllci5hbHBoYSA9IDAuNixvdXRsaWVyLnNpemUgPSAwLjcsd2lkdGg9MC42KSsKICAgIGdlb21fcG9pbnQoc3RhdCA9ICJzdW1tYXJ5IiwgZnVuID0gIm1lYW4iLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkrCiAgICB5bGFiKCJUYWppbWEncyBEIikreGxhYigiIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41LDIuNSwzLjUpLCBjb2xvcj0iZ3JheSIsIHNpemU9MC41KQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvVGFqaW1hRF9QV1NfZnJvbUJhbS5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMuNSkKCmBgYAohW10oLi4vT3V0cHV0L1NGUy9UYWppbWFEX1BXU19mcm9tQmFtLnBuZyl7d2lkdGg9NTAlfQoKIyMgRXN0aW1hdGUgU0ZTIGZyb20gVkNGIGZpbGVzIAooVXNpbmcgbWFmMC4wMCAtbm8gbG93IGFsbGVsZSBmcmVxIGN1dG9mZikKClN0ZXAgMTogUnVuIEJDMTdfYW5nc2RfU0ZTLnNoIChpbiAiL0RhdGEvU2x1cnVtc2NyaXB0cy9TRlNfZnJvbVZDRm1hZjAwLyIpIGZvciBlYWNoIHBvcHVsYXRpb24gLSB0aGlzIHdpbGwgY2FsY3VsYXRlIHNmcywgdGhldGEgZm9yIGJvdGggZm9sZGVkIGFuZCB1bmZvbGRlZCBTRlMuIAoKU3RlcCAyOiBDcmVhdGUgMkQgU0ZTIGJ5IHJ1bm5pbmcgZWFjaCBjb21iaW5hdGlvbiAoZXguIEJDMTdDQTE3MkRTRlMuc2ggaW4gIi9EYXRhL1NsdXJ1bXNjcmlwdHMvU0ZTX2Zyb21WQ0ZtYWYwMC8iKSAKClN0ZXAgMzogQ2FsY3VsYXRlIEZzdC9QYnMgZm9yIHBvcHVsYXRpb24gY29tYmluYXRpb25zIGJ5IHJ1bm5pbmcgM0RGc3Qgc2NyaXB0cyAoZXguIDNERnN0X3B3czEuc2gpIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI1Bsb3QgMkQgU0ZTIChTZnNfY29tcGFyaXNvbi5SKQpzb3VyY2UoIi4uL1JzY3JpcHRzL0Jhc2VTY3JpcHRzLlIiKQoKIyMgMkQgU0ZTCiMgVGhlIG91dHB1dCBmcm9tIEFOR1NEIGlzIGEgZmxhdHRlbiBtYXRyaXg6IGVhY2ggdmFsdWUgaXMgdGhlIGNvdW50IG9mIHNpdGVzIHdpdGggdGhlIGNvcnJlc3BvbmRpbmcgam9pbnQgZnJlcXVlbmN5IG9yZGVyZWQgYXMKIyBbMCwwXSBbMCwxXSBbMCwyXSAuLgoKIyBmdW5jdGlvbiB0byBjcmVhdGUgYSBtYXRyaXggZnJvbSBBTkdTRCBvdXRwdXQgKGEgZmxhdHRlbiBtYXRyaXgpCnZlYzJtYXQ8LWZ1bmN0aW9uKHZlYywgbjEsbjIsIHBvcDEsIHBvcDIpewogICAgbjE8LW4xCiAgICBuMjwtbjIKICAgIHBvcDE8LXBvcDEKICAgIHBvcDI8LXBvcDIKICAgIEFOR1NELjJELlNGUyA8LSBzY2FuKHBhc3RlKHZlYywgc2VwPSIiKSwgcXVpZXQ9VCkKICAgIEFOR1NELjJELlNGUyA8LSB0KG1hdHJpeChBTkdTRC4yRC5TRlMsIG5yb3c9bjIqMisxLCBuY29sPW4xKjIrMSkpCiAgICAjIG1hc2sgbm9uLXZhcmlhbnQgc2l0ZXMKICAgIEFOR1NELjJELlNGU1sxLDFdIDwtIDAKICAgIEFOR1NELjJELlNGU1tucm93KEFOR1NELjJELlNGUyksbmNvbChBTkdTRC4yRC5TRlMpXSA8LSAwCiAgICBkZjwtZGF0YS5mcmFtZShBTkdTRC4yRC5TRlMpCiAgICBjb2xuYW1lcyhkZik8LTA6KG5jb2woZGYpLTEpCiAgICBkZiRjb3VudDwtMDoobnJvdyhkZiktMSkKICAgIHJldHVybihkZikKfQoKI1Bsb3QgMkQgU0ZTIGhlYXRtYXAgICAgIApwb3BzLmluZm88LXJlYWQuY3N2KCIuLi9EYXRhL1NhbXBsZV9tZXRhZGF0YV84OTJwb3BzLmNzdiIpCnBvcHMuaW5mbyR5cjwtJycKcG9wcy5pbmZvJHlyW3BvcHMuaW5mbyR5ZWFyPT05Nnxwb3BzLmluZm8keWVhcj09OTFdPC1wYXN0ZTAoMTkscG9wcy5pbmZvJHllYXJbcG9wcy5pbmZvJHllYXI9PTk2fHBvcHMuaW5mbyR5ZWFyPT05MV0pCnBvcHMuaW5mbyR5cltwb3BzLmluZm8keWVhcj09MDd8cG9wcy5pbmZvJHllYXI9PTA2fHBvcHMuaW5mbyR5ZWFyPT0xN108LXBhc3RlMCgyMCxwb3BzLmluZm8keWVhcltwb3BzLmluZm8keWVhcj09MDd8cG9wcy5pbmZvJHllYXI9PTA2fHBvcHMuaW5mbyR5ZWFyPT0xN10pCnBvcHMuaW5mbyR5cjwtYXBwbHkocG9wcy5pbmZvWyJ5ciJdLCAxLCBmdW5jdGlvbih4KSB7aWYoeD09MjA2KSB4PTIwMDYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh4PT0yMDcpIHg9MjAwNwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB4PXh9KQpwb3BzLmluZm8keXI8LWFzLmludGVnZXIocG9wcy5pbmZvJHlyKQpwb3BzPC11bmlxdWUocG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcikKCnB3c3M8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKdGJzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IikKc3NzPC1jKCJTUzk2IiwiU1MwNiIsIlNTMTciKQp5MTc8LXBvcHNbZ3JlcCgiMTciLHBvcHMpXQpjb21iMTwtY29tYm4ocHdzcywgMikKY29tYjE8LXQoY29tYjEpCmNvbWIyPC1jb21ibih0YnMsIDIpCmNvbWIyPC10KGNvbWIyKQpjb21iMzwtY29tYm4oc3NzLCAyKQpjb21iMzwtdChjb21iMykKY29tYjQ8LWNvbWJuKHkxNywgMikKY29tYjQ8LXQoY29tYjQpCgojaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDk2ODkwNjkvaGVhdG1hcC13aXRoLWNvbnRpbnVvdXMtcmFpbmJvdy1jb2xvdXJzCmNvbHMgPC0gcmV2KHJhaW5ib3coNylbLTddKSAjcmFpbmJvdyBjb2xvcnMgZm9yIGhlYXRtYXAKCiNQV1MKUGxvdHM8LWxpc3QoKQpzZnMucHdzPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYjEpKXsKICAgIHBvcDE8LWNvbWIxW2ksMV0KICAgIHBvcDI8LWNvbWIxW2ksMl0KICAgIG4xPC1ucm93KHBvcHMuaW5mb1twb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AxLF0pCiAgICBuMjwtbnJvdyhwb3BzLmluZm9bcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMixdKQogICAgCiAgICBzZnMxPC12ZWMybWF0KHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZm9sZGVkXyIscG9wMSwiXyIscG9wMiwiX21hZjAwLnNmcyIpLCBuMT1uMSwgbjI9bjIsIHBvcDE9cG9wMSwgcG9wMj1wb3AyKQogICAgCiAgICBpZiAocG9wcy5pbmZvJHlyW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDFdWzFdPnBvcHMuaW5mbyR5cltwb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AyXVsxXSl7CiAgICAgICAgc2ZzMTwtZGF0YS5mcmFtZSh0KHNmczFbLDE6KG5jb2woc2ZzMSktMSldKSkKICAgICAgICBjb2xuYW1lcyhzZnMxKTwtMDoobmNvbChzZnMxKS0xKQogICAgICAgIHNmczEkY291bnQ8LTA6KG5yb3coc2ZzMSktMSkKICAgICAgICBwMjwtcG9wMgogICAgICAgIHBvcDI8LXBvcDEKICAgICAgICBwb3AxPC1wMgogICAgfQogICAgI1Bsb3QgZmlyc3QgMzAKICAgIHNmczI8LXNmczFbMTozMCwxOjMwXQogICAgc2ZzMiRjb3VudDwtMDoobnJvdyhzZnMyKS0xKQogICAgc2ZzbTI8LW1lbHQoc2ZzMiwgaWQudmFycz0iY291bnQiKQogICAgc2ZzbTIkdmFyaWFibGU8LWFzLmludGVnZXIoYXMuY2hhcmFjdGVyKHNmc20yJHZhcmlhYmxlKSkKICAgIAogICAgI3plcm8gYXMgd2hpdGUgKHJlcGxhY2Ugd2l0aCBOQSkKICAgIHNmc20yJHZhbHVlW3Nmc20yJHZhbHVlPT0wXTwtTkEKICAgIHNmc20yJHBvcDE8LXBvcDEKICAgIHNmc20yJHBvcDI8LXBvcDIKICAgIHNmcy5wd3M8LXJiaW5kKHNmcy5wd3MsIHNmc20yKQp9CgpzZnMucHdzJHBvcDE8LWZhY3RvcihzZnMucHdzJHBvcDEsIGxldmVscz1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpKQpzZnMucHdzJHBvcDI8LWZhY3RvcihzZnMucHdzJHBvcDIsIGxldmVscz1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpKQoKZ2dwbG90KHNmcy5wd3MsIGFlcyh4PWNvdW50LCB5PXZhcmlhYmxlKSkrCiAgICBmYWNldF9ncmlkKHBvcDJ+cG9wMSkrCiAgICBnZW9tX3Jhc3RlcihhZXMoZmlsbD1sb2cxMCh2YWx1ZSkpKSt4bGFiKCcnKSt5bGFiKCIiKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jb2xzLCBuYW1lPSJsb2coIyBvZiBhbGxlbGVzKSIsIG5hLnZhbHVlID0gIndoaXRlIikrCiAgICB0aGVtZV9taW5pbWFsKCkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL3Nmc18yRF9QV1MucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkKICAgCgojVEIKc2ZzLnRiPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYjIpKXsKICAgIHBvcDE8LWNvbWIyW2ksMV0KICAgIHBvcDI8LWNvbWIyW2ksMl0KICAgIG4xPC1ucm93KHBvcHMuaW5mb1twb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AxLF0pCiAgICBuMjwtbnJvdyhwb3BzLmluZm9bcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMixdKQogICAgCiAgICBzZnMxPC12ZWMybWF0KHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZm9sZGVkXyIscG9wMSwiXyIscG9wMiwiX21hZjAwLnNmcyIpLCBuMT1uMSwgbjI9bjIsIHBvcDE9cG9wMSwgcG9wMj1wb3AyKQogICAgCiAgICBpZiAocG9wcy5pbmZvJHlyW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDFdWzFdPnBvcHMuaW5mbyR5cltwb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AyXVsxXSl7CiAgICAgICAgc2ZzMTwtZGF0YS5mcmFtZSh0KHNmczFbLDE6KG5jb2woc2ZzMSktMSldKSkKICAgICAgICBjb2xuYW1lcyhzZnMxKTwtMDoobmNvbChzZnMxKS0xKQogICAgICAgIHNmczEkY291bnQ8LTA6KG5yb3coc2ZzMSktMSkKICAgICAgICBwMjwtcG9wMgogICAgICAgIHBvcDI8LXBvcDEKICAgICAgICBwb3AxPC1wMgogICAgfQogICAgI1Bsb3QgZmlyc3QgMzAKICAgIHNmczI8LXNmczFbMTozMCwxOjMwXQogICAgc2ZzMiRjb3VudDwtMDoobnJvdyhzZnMyKS0xKQogICAgc2ZzbTI8LW1lbHQoc2ZzMiwgaWQudmFycz0iY291bnQiKQogICAgc2ZzbTIkdmFyaWFibGU8LWFzLmludGVnZXIoYXMuY2hhcmFjdGVyKHNmc20yJHZhcmlhYmxlKSkKICAgIAogICAgI3plcm8gYXMgd2hpdGUgKHJlcGxhY2Ugd2l0aCBOQSkKICAgIHNmc20yJHZhbHVlW3Nmc20yJHZhbHVlPT0wXTwtTkEKICAgIHNmc20yJHBvcDE8LXBvcDEKICAgIHNmc20yJHBvcDI8LXBvcDIKICAgIHNmcy50YjwtcmJpbmQoc2ZzLnRiLCBzZnNtMikKfQoKc2ZzLnRiJHBvcDE8LWZhY3RvcihzZnMudGIkcG9wMSwgbGV2ZWxzPWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciKSkKc2ZzLnRiJHBvcDI8LWZhY3RvcihzZnMudGIkcG9wMiwgbGV2ZWxzPWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciKSkKCmdncGxvdChzZnMudGIsIGFlcyh4PWNvdW50LCB5PXZhcmlhYmxlKSkrCiAgICBmYWNldF9ncmlkKHBvcDJ+cG9wMSkrCiAgICBnZW9tX3Jhc3RlcihhZXMoZmlsbD1sb2cxMCh2YWx1ZSkpKSt4bGFiKCcnKSt5bGFiKCIiKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jb2xzLCBuYW1lPSJsb2coIyBvZiBhbGxlbGVzKSIsIG5hLnZhbHVlID0gIndoaXRlIikrCiAgICB0aGVtZV9taW5pbWFsKCkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL3Nmc18yRF9UQi5wbmciLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCBkcGk9MzAwKQoKI1NTCnNmcy5zczwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOiBucm93KGNvbWIzKSl7CiAgICBwb3AxPC1jb21iM1tpLDFdCiAgICBwb3AyPC1jb21iM1tpLDJdCiAgICBuMTwtbnJvdyhwb3BzLmluZm9bcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMSxdKQogICAgbjI8LW5yb3cocG9wcy5pbmZvW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDIsXSkKICAgIHNmczE8LXZlYzJtYXQocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mb2xkZWRfIixwb3AxLCJfIixwb3AyLCJfbWFmMDAuc2ZzIiksIG4xPW4xLCBuMj1uMiwgcG9wMT1wb3AxLCBwb3AyPXBvcDIpCiAgICBpZiAocG9wcy5pbmZvJHlyW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDFdWzFdPnBvcHMuaW5mbyR5cltwb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AyXVsxXSl7CiAgICAgICAgc2ZzMTwtZGF0YS5mcmFtZSh0KHNmczFbLDE6KG5jb2woc2ZzMSktMSldKSkKICAgICAgICBjb2xuYW1lcyhzZnMxKTwtMDoobmNvbChzZnMxKS0xKQogICAgICAgIHNmczEkY291bnQ8LTA6KG5yb3coc2ZzMSktMSkKICAgICAgICBwMjwtcG9wMgogICAgICAgIHBvcDI8LXBvcDEKICAgICAgICBwb3AxPC1wMgogICAgfQogICAgI1Bsb3QgZmlyc3QgMzAKICAgIHNmczI8LXNmczFbMTozMCwxOjMwXQogICAgc2ZzMiRjb3VudDwtMDoobnJvdyhzZnMyKS0xKQogICAgc2ZzbTI8LW1lbHQoc2ZzMiwgaWQudmFycz0iY291bnQiKQogICAgc2ZzbTIkdmFyaWFibGU8LWFzLmludGVnZXIoYXMuY2hhcmFjdGVyKHNmc20yJHZhcmlhYmxlKSkKICAgIAogICAgI3plcm8gYXMgd2hpdGUgKHJlcGxhY2Ugd2l0aCBOQSkKICAgIHNmc20yJHZhbHVlW3Nmc20yJHZhbHVlPT0wXTwtTkEKICAgIHNmc20yJHBvcDE8LXBvcDEKICAgIHNmc20yJHBvcDI8LXBvcDIKICAgIHNmcy5zczwtcmJpbmQoc2ZzLnNzLCBzZnNtMikKfQpzZnMuc3MkcG9wMTwtZmFjdG9yKHNmcy5zcyRwb3AxLCBsZXZlbHM9YygiU1M5NiIsIlNTMDYiLCJTUzE3IikpCnNmcy5zcyRwb3AyPC1mYWN0b3Ioc2ZzLnNzJHBvcDIsIGxldmVscz1jKCJTUzk2IiwiU1MwNiIsIlNTMTciKSkKCmdncGxvdChzZnMuc3MsIGFlcyh4PWNvdW50LCB5PXZhcmlhYmxlKSkrCiAgICBmYWNldF9ncmlkKHBvcDJ+cG9wMSkrCiAgICBnZW9tX3Jhc3RlcihhZXMoZmlsbD1sb2codmFsdWUpKSkreGxhYignJykreWxhYigiIikrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Y29scywgbmFtZT0ibG9nKCMgb2YgYWxsZWxlcykiLCBuYS52YWx1ZSA9ICJ3aGl0ZSIpKwogICAgdGhlbWVfbWluaW1hbCgpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9zZnNfMkRfU1MucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkKCiMyMDE3IHBvcHMKc2ZzMTc8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iNCkpewogICAgcG9wMTwtY29tYjRbaSwxXQogICAgcG9wMjwtY29tYjRbaSwyXQogICAgbjE8LW5yb3cocG9wcy5pbmZvW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDEsXSkKICAgIG4yPC1ucm93KHBvcHMuaW5mb1twb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AyLF0pCiAgICBzZnMxPC12ZWMybWF0KHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZm9sZGVkXyIscG9wMSwiXyIscG9wMiwiX21hZjAwLnNmcyIpLCBuMT1uMSwgbjI9bjIsIHBvcDE9cG9wMSwgcG9wMj1wb3AyKQogICAgCiAgICAjUGxvdCBmaXJzdCAzMAogICAgc2ZzMjwtc2ZzMVsxOjMwLDE6MzBdCiAgICBzZnMyJGNvdW50PC0wOihucm93KHNmczIpLTEpCiAgICBzZnNtMjwtbWVsdChzZnMyLCBpZC52YXJzPSJjb3VudCIpCiAgICBzZnNtMiR2YXJpYWJsZTwtYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIoc2ZzbTIkdmFyaWFibGUpKQogICAgCiAgICAjemVybyBhcyB3aGl0ZSAocmVwbGFjZSB3aXRoIE5BKQogICAgc2ZzbTIkdmFsdWVbc2ZzbTIkdmFsdWU9PTBdPC1OQQogICAgc2ZzbTIkcG9wMTwtcG9wMQogICAgc2ZzbTIkcG9wMjwtcG9wMgogICAgc2ZzMTc8LXJiaW5kKHNmczE3LCBzZnNtMikKfQoKc2ZzMTckcG9wMTwtZmFjdG9yKHNmczE3JHBvcDEsIGxldmVscz1wYXN0ZSh5MTcpKQpzZnMxNyRwb3AyPC1mYWN0b3Ioc2ZzMTckcG9wMiwgbGV2ZWxzPXBhc3RlKHkxNykpCgpnZ3Bsb3Qoc2ZzMTcsIGFlcyh4PWNvdW50LCB5PXZhcmlhYmxlKSkrCiAgICBmYWNldF9ncmlkKHBvcDJ+cG9wMSkrCiAgICBnZW9tX3Jhc3RlcihhZXMoZmlsbD1sb2codmFsdWUpKSkreGxhYignJykreWxhYigiIikrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Y29scywgbmFtZT0ibG9nKCMgb2YgYWxsZWxlcykiLCBuYS52YWx1ZSA9ICJ3aGl0ZSIpKwogICAgdGhlbWVfbWluaW1hbCgpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9zZnNfMkRfMjAxNy5wbmciLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAxNiwgZHBpPTMwMCkKYGBgCgojIyMgMUQgU0ZTIGFsbCBwb3B1bGF0aW9ucyAoRG93bnNhbXBsZWQgYmFtIGZpbGVzKSAgCiFbXSguLi9PdXRwdXQvU0ZTLzFEU0ZTX2FsbF9kb3duc2FtcGxlZC5wbmcpICAKCiMjIyAyRCBTRlMgUFdTICAKIVtdKC4uL091dHB1dC9TRlMvc2ZzXzJEX1BXUy5wbmcpe3dpZHRoPTUwJX0KCiMjIyAyRCBTRlMgVEIgICAgCiFbXSguLi9PdXRwdXQvU0ZTL3Nmc18yRF9UQi5wbmcpe3dpZHRoPTUwJX0KCiMjIyAyRCBTRlMgU1MgICAKIVtdKC4uL091dHB1dC9TRlMvc2ZzXzJEX1NTLnBuZyl7d2lkdGg9NTAlfSAgCgojIyMgMkQgU0ZTICgyMDE3KSAgICAgCiFbXSguLi9PdXRwdXQvU0ZTL3Nmc18yRF8yMDE3LnBuZyl7d2lkdGg9NzAlfSAgCgoKIyBGc3QgYmV0d2VlbiB5ZWFycyBwZXIgcG9wdWxhdGlvbiAKCiMjIFBXUyAgCgojIyMgRnN0IGFsb25nIHRoZSBnZW5vbWUKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyMgRnN0IGVzdGltYXRlcyBmcm9tIDJEc2ZzCnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKY29tYjwtdChjb21ibihwb3BzLDIpKQoKZnN0PC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1yZWFkLmRlbGltKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZnN0XyIscG9wMSwiXyIscG9wMiwiXzUwa1dpbmRvd19tYWYwMCIpKQogICAgY29uYW1lczwtY29sbmFtZXMoZGYpWzI6NF0KICAgIGNvbG5hbWVzKGRmKVs0XTwtIkZzdCIKICAgIGNvbG5hbWVzKGRmKVsxOjNdPC1jb25hbWVzCiAgICBkZiRwb3A8LXBhc3RlMChwb3AxLCIudnMuIixwb3AyKQogICAgZGYkY2g9YXMuaW50ZWdlcihnc3ViKCJjaHIiLCIiLCBkZiRjaHIpKQogICAgZGY8LWRmW29yZGVyKGRmJGNoKSxdCiAgICBkZiRsb2M8LTE6bnJvdyhkZikKICAgIGZzdDwtcmJpbmQoZnN0LCBkZikKfQoKZXZlbnM8LXBhc3RlMCgiY2hyIixzZXEoMiwyNiwgYnk9MikpCiNQbG90IEZzdCB2YWx1ZXNlIGFjcm9zcyBHZW5vbWUKZnN0JGNvbG9yPC0iY29sMSIKZnN0JGNvbG9yW2ZzdCRjaHIgJWluJSBldmVuc108LSJjb2wyIgpmc3QkcG9wPC1mYWN0b3IoZnN0JHBvcCwgbGV2ZWxzPXVuaXF1ZShmc3QkcG9wKSkKCiNhZGQgY2hyb21vc29tZSBudW1iZXIKZGY8LWZzdFtmc3QkcG9wPT0iUFdTOTEudnMuUFdTOTYiLF0Kcm93czwtZGF0YS5mcmFtZShjaHI9MToyNikKZm9yIChpIGluIDE6MjYpewogICAgaWYgKGkgPT0xKXsKICAgICAgICByb3dzJG5baV08LW5yb3coZGZbZGYkY2g9PWksXSkKICAgICAgICByb3dzJG1pZGRsZVtpXTwtLW5yb3coZGZbZGYkY2g9PWksXSkvMgogICAgfQogICAgaWYgKGkgPjEpewogICAgICAgIHJvd3MkbltpXTwtbnJvdyhkZltkZiRjaD09aSxdKQogICAgICAgIHJvd3MkbWlkZGxlW2ldPC1zdW0ocm93cyRuWzE6KGktMSldKStyb3dzJG5baV0vMgogICAgfQp9CiMKZ2dwbG90KGZzdCwgYWVzKHg9bG9jLCB5PUZzdCwgY29sb3I9Y29sb3IpKSsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEsIHN0cmlwLnBvc2l0aW9uPSJyaWdodCIpKwogICAgZ2VvbV9wb2ludChzaXplPTAuMikrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImdyYXk1MCIsInN0ZWVsYmx1ZSIpKSsKICAgIHRoZW1lX2J3KCkrCiAgICB5bGFiKCJGc3QiKSt4bGFiKCdHZW5vbWUgcG9zaXRpb24nKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1yb3dzJG1pZGRsZSwgbGFiZWxzPTE6MjYpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9QV1NfRnN0X3BhaXJ3aXNlX2NvbXBhcmlzb24ucG5nIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTAsIGRwaT0xNTApCmBgYAohW1BhaXJ3aXNlIEZzdCBhbG9uZyB0aGUgZ2Vub21lXSguLi9PdXRwdXQvU0ZTL1BXU19Gc3RfcGFpcndpc2VfY29tcGFyaXNvbi5wbmcpICAKIyMjIFBhaXJ3aXNlIEZzdCBhbG9uZyBlYWNoIGNocm9tb3NvbWUKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgUGxvdCBGc3QgdmFsdWVzIGFsb25nIGVhY2ggY2hyb21vc29tZQpmc3QkY2hyPC1mYWN0b3IoZnN0JGNociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKZnN0cHc8LWZzdApwbG90czwtbGlzdCgpCmNvbXBhcmU8LXBhc3RlMCh1bmlxdWUoZnN0cHckcG9wKSkKbWF4KGZzdHB3JEZzdCkKZm9yIChpIGluIDE6Nil7IAogICAgZnM8LWdzdWIoInZzLiIsIiIsY29tcGFyZVtpXSkKICAgIHBvcHMgPC0gdW5saXN0KHN0cnNwbGl0KGZzLCAiXFwuIikpCiAgICBtYXh5PC1tYXgoZnN0cHckRnN0W2ZzdHB3JHBvcD09Y29tcGFyZVtpXV0pCiAgICAjIEZzdCB3aXRoIGFjdHVhbCBsaW5lIHRvIGhpZ2hsaWdodCB0aGUgZGlmZmVyZW5jZXMKICAgIHBsb3RzW1tpXV0gPC0gZ2dwbG90KGZzdHB3W2ZzdHB3JHBvcD09Y29tcGFyZVtpXSxdLCBhZXMoeCA9bWlkUG9zLCB5ID1Gc3QgKSkgKyAKICAgICAgICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9IGdyeSxhbHBoYSA9IDAuNCwgc2hhcGUgPSAxKSsKICAgICAgICB0aGVtZV9taW5pbWFsKCkreWxpbSgwLG1heHkrMC4wMikrCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSsKICAgICAgICB5bGFiKCJGc3RcbiIpKyB4bGFiKCIiKSsgCiAgICAgICAgZ2d0aXRsZShwYXN0ZTAocG9wc1sxXSwiIHZzLiIsIHBvcHNbMl0pKSsKICAgICAgICBnZW9tX2xpbmUoY29sb3I9Ymx1LCBzaXplPTAuMikrCiAgICAgICAgZmFjZXRfd3JhcCh+Y2hyLCBuY29sID0gOSkKfQojc2F2ZSB0aGUgcGxvdHMgdG9nZXRoZXIKe3BuZyhwYXN0ZTAoIi4uL091dHB1dC9TRlMvUFdTX0ZzdF9tYWYwMF9jaHIucG5nIiksIGhlaWdodCA9IDgsIHdpZHRoID0gMTgsIHJlcz0xNTAsIHVuaXRzID0gImluIikKZ3JpZC5hcnJhbmdlKHBsb3RzW1szXV0sIHBsb3RzW1syXV0sIHBsb3RzW1s0XV0sIHBsb3RzW1sxXV0scGxvdHNbWzVdXSxwbG90c1tbNl1dLCBuY29sPTMpCmRldi5vZmYoKX0KYGBgCiFbUGFpcndpc2UgRnN0IGZvciBlYWNoIGdlbm9tZV0oLi4vT3V0cHV0L1NGUy9QV1NfRnN0X21hZjAwX2Noci5wbmcpICAKICAKCiMjIyBDcmVhdGUgcGFpcndpc2UgRnN0IG1hdHJpeApgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIC4uY29udGludWVkIGZyb20gYWJvdmUgCnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKY29tYjwtdChjb21ibihwb3BzLDIpKQoKIyMgUGxvdCBhdmVyYWdlIGZzdCBpbiBhIGhlYXRtYXAKY29tcDwtdW5pcXVlKGZzdCRwb3ApCnBhaXJmc3Q8LWRhdGEuZnJhbWUobWF0cml4KG5jb2w9NCwgbnJvdz00KSwgcm93Lm5hbWVzPXBvcHMpCmNvbG5hbWVzKHBhaXJmc3QpPC1wb3BzCmZvciAoaSBpbiAxOjYpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1mc3RbZnN0JHBvcD09Y29tcFtpXSxdCiAgICBwYWlyZnN0W3BvcDEscG9wMl08LW1lYW4oZGYkRnN0LCBuYS5ybT1UKQogICAgI3BhaXJmc3RbcG9wMixwb3AxXTwtbWVhbihkZiRGc3QsIG5hLnJtPVQpCn0Kd3JpdGUuY3N2KHBhaXJmc3QsIi4uL091dHB1dC9TRlMvUFdTX3BhaXJ3aXNlRnN0X21hdHJpeC5jc3YiKQoKcGFpcmZzdDwtcmVhZC5jc3YoIi4uL091dHB1dC9TRlMvUFdTX3BhaXJ3aXNlRnN0X21hdHJpeC5jc3YiLCByb3cubmFtZXMgPSAxKQpkZjwtcGFpcmZzdApkaWFnKGRmKTwtMApkZiRwb3A8LXJvd25hbWVzKGRmKQpkZm08LW1lbHQoZGYsbmEucm09VCwgaWQudmFycz0ncG9wJykKCiNOQSB0byBkaWFnb25hbApkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKZGZtJHBvcDwtZmFjdG9yKGRmbSRwb3AsIGxldmVscz1wb3BzKQpkZm0kdmFsdWU8LXJvdW5kKGRmbSR2YWx1ZSwgNCkKZ2dwbG90KGRhdGEgPSBkZm0sIGFlcyhwb3AsIHZhcmlhYmxlLCBmaWxsID0gdmFsdWUpKSsKICAgIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWMoIndoaXRlIiwgIiMwQzU0RkYiKSwgbGltaXRzPWMoMCwgKG1heChkZm0kdmFsdWUsIG5hLnJtPVQpKzAuMDA1KSksbmEudmFsdWU9ImdyYXk4MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iRnN0IikrCiAgICB0aGVtZV9taW5pbWFsKCkrIHhsYWIoIiIpK3lsYWIoIiIpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCB2anVzdCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSkpKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkrCiAgICBjb29yZF9maXhlZCgpKwogICAgZ2VvbV90ZXh0KGFlcyhwb3AsIHZhcmlhYmxlLCBsYWJlbCA9IHZhbHVlKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNSkKZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9wYWlyd2lzZUZzdF9QV1MucG5nIiksIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSwgZHBpPTE1MCkKYGBgCiFbUFdTIFBhaXJ3aXNlIEZzdF0oLi4vT3V0cHV0L1NGUy9wYWlyd2lzZUZzdF9QV1MucG5nKXt3aWR0aD01MCV9CgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgUGxvdCBGc3QgaW4gYSBiYXIgcGxvdCBvcmRlcmVkIGFuZCBjb2xvcmVkIGluIHRoZSBzYW1lIHdheSBhcyBGc3QvUGkgc2h1ZmZsZSByZXN1bHRzIChTaHVmZmxpbmdfcGkuZnN0LnRlaGF0LlJtZCkKZnN0czwtZGZtWyFpcy5uYShkZm0kdmFsdWUpLF0KZnN0cyRjb21wPC1wYXN0ZTAoZnN0cyRwb3AsIl8iLGZzdHMkdmFyaWFibGUpCgojc2V0IHRoZSBjb2xvcnMKZGl2MTwtZGl2ZXJnaW5nX2hjbCg2LCBwYWxldHRlPSJCbHVlLVJlZCIpCmRpdjI8LXJldihkaXYxKQpuYW1lcyhkaXYyKTwtYygiUFdTOTZfUFdTMDciLCJQV1MwN19QV1MxNyIsIlBXUzkxX1BXUzk2IiwgIlBXUzkxX1BXUzA3IiwgIlBXUzkxX1BXUzE3IiwiUFdTOTZfUFdTMTciKQpmc3RzPC1mc3RzW29yZGVyKGZzdHMkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCmZzdHMkY29tcDwtZmFjdG9yKGZzdHMkY29tcCwgbGV2ZWxzPXBhc3RlMCh1bmlxdWUoZnN0cyRjb21wKSkpCgpnZ3Bsb3QoZnN0cywgYWVzKHg9Y29tcCwgeT12YWx1ZSwgZmlsbD1jb21wKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJjb21wIix2YWx1ZXMgPSBkaXYyKSsKICAgIHhsYWIoJycpK3lsYWIoJ0ZzdCcpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9QYWlyd2lzZUZzdF9vcmRlcmVkLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCiNGc3Qgb3ZlciB0aW1lCgpmc3RzMjwtZnN0c1tmc3RzJGNvbXAgJWluJSBjKCJQV1M5MV9QV1M5NiIsIlBXUzk2X1BXUzA3IiwiUFdTMDdfUFdTMTciKSxdCmZzdHMyJHRpbWU8LTEKZnN0czIkdGltZVtmc3RzMiRjb21wPT0iUFdTOTZfUFdTMDciXTwtMgpmc3RzMiR0aW1lW2ZzdHMyJGNvbXA9PSJQV1MwN19QV1MxNyJdPC0zCgpnZ3Bsb3QoZnN0czIsIGFlcyh4PXRpbWUsIHk9dmFsdWUpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zLCBjb2xvcj0ic3RlZWxibHVlIikrCiAgICBnZW9tX3BhdGgoY29sb3I9InN0ZWVsYmx1ZSIpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjkxLTk2IiwgIjk2LTA3IiwiMDctMTciKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZS5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgpmc3RzJHNlcmllczwtIjE5OTEtMjAwNywgMTk5MS0yMDE3Igpmc3RzJHNlcmllc1tmc3RzJGNvbXAgJWluJSBjKCJQV1M5MV9QV1M5NiIsIlBXUzk2X1BXUzA3IiwiUFdTMDdfUFdTMTciKV08LSIxOTkxLTE5OTYsIDE5OTYtMjAwNywgMjAwNy0yMDE3Igpmc3RzJHNlcmllc1tmc3RzJGNvbXAgPT0iUFdTOTZfUFdTMTciXTwtIjE5OTYtMjAxNyIKZnN0cyR0aW1lPC0xCmZzdHMkdGltZVtmc3RzJHZhcmlhYmxlPT0iUFdTMTciXTwtMwpmc3RzJHRpbWVbZnN0cyR2YXJpYWJsZT09IlBXUzA3Il08LTIKc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKCmdncGxvdChmc3RzLCBhZXMoeD10aW1lLCB5PXZhbHVlLCBjb2xvcj1zZXJpZXMpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zKSsKICAgIGdlb21fcGF0aCgpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzKSsKICAgIHRoZW1lX2NsYXNzaWMoKSt5bGFiKCJGc3QiKSt4bGFiKCIiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxLDIsMyksIGxhYmVscz1jKCIxOTkxLTE5OTYiLCAifjIwMDciLCJ+MjAxNyIpKSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV9hbGxDb21wYXJpc29uLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCgpmc3RQMTwtZnN0cwpmc3RQMjwtZnN0czIKYGBgCgohW10oLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWUucG5nKSAgCgoKIVtdKC4uL091dHB1dC9Gc3QvRnN0X292ZXJUaW1lX2FsbENvbXBhcmlzb24ucG5nKSAgCgoKIyMjIFBsb3QgbWVhbiBGc3QgZm9yIGVhY2ggY2hyb21vc29tZSAgCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgUGxvdCBtZWFuIEZzdCBvZiBlYWNoIGNocm9tb3NtZQpGc3Q8LWRhdGEuZnJhbWUoKQpjb21wYXJlPC1wYXN0ZTAodW5pcXVlKGZzdHB3JHBvcCkpCmZvciAoaiBpbiAxOjI2KXsKICAgIGZzdC5jaDwtZnN0W2ZzdCRjaD09aixdCiAgICBwYWlyY2g8LWRhdGEuZnJhbWUobWF0cml4KG5jb2w9NCwgbnJvdz00KSwgcm93Lm5hbWVzPXBvcHMpCiAgICBjb2xuYW1lcyhwYWlyY2gpPC1wb3BzCiAgICBmb3IgKGkgaW4gMTo2KXsKICAgICAgICBwb3AxPC1jb21iW2ksMV0KICAgICAgICBwb3AyPC1jb21iW2ksMl0KICAgICAgICBkZjwtZnN0LmNoW2ZzdC5jaCRwb3A9PWNvbXBhcmVbaV0sXQogICAgICAgIHBhaXJjaFtwb3AxLHBvcDJdPC1tZWFuKGRmJEZzdCwgbmEucm09VCkKICAgIH0KICAgIGRpYWcocGFpcmNoKTwtMAogICAgcGFpcmNoJHBvcDwtcm93bmFtZXMocGFpcmNoKQogICAgZGZtPC1tZWx0KHBhaXJjaCxuYS5ybT1ULCBpZC52YXJzPSdwb3AnKQogICAgCiAgICAjTkEgdG8gZGlhZ29uYWwKICAgIGRmbSR2YWx1ZVtkZm0kdmFsdWU9PTBdPC1OQQogICAgZGZtJHBvcDwtZmFjdG9yKGRmbSRwb3AsIGxldmVscz1wb3BzKQogICAgZGZtJHZhbHVlPC1yb3VuZChkZm0kdmFsdWUsIDQpCiAgICBkZm0kY2hyPC1qCiAgICBGc3Q8LXJiaW5kKEZzdCwgZGZtKQogICAgCn0KRnN0JGlkPC1wYXN0ZTAoRnN0JHBvcCwiIHZzLiIsRnN0JHZhcmlhYmxlKQpGc3Q8LUZzdFshaXMubmEoRnN0JHZhbHVlKSxdCmdncGxvdChGc3QsIGFlcyh4PWNociwgeT12YWx1ZSxjb2xvcj1pZCkpKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9wYXRoKHN0YXQ9ImlkZW50aXR5IikrCiAgICB0aGVtZV9taW5pbWFsKCkreWxhYigiRnN0IikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPTE6MjYsIGxhYmVscyA9IDE6MjYpKwogICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9QV1NfRnN0X2J5Q2hyb21vc29tZV9kb3RwbG90LnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0PTQuNSwgZHBpPTE1MCkKYGBgCiFbUFdTIGF2ZXJhZ2UgRnN0IHBlciBjaHJvbW9zb21lXSguLi9PdXRwdXQvU0ZTL1BXU19Gc3RfYnlDaHJvbW9zb21lX2RvdHBsb3QucG5nKXt3aWR0aD04MCV9ICAKCjxicj4KCiMjIFRvZ2lhayBCYXkKIyMjIFBhaXJ3aXNlIEZzdCBhbG9uZyB0aGUgZ2Vub21lICAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBvcHM8LWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciKQpjb21iPC10KGNvbWJuKHBvcHMsMikpCgpmc3Q8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgZGY8LXJlYWQuZGVsaW0ocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mc3RfIixwb3AxLCJfIixwb3AyLCJfNTBrV2luZG93X21hZjAwIikpCiAgICBjb25hbWVzPC1jb2xuYW1lcyhkZilbMjo0XQogICAgY29sbmFtZXMoZGYpWzRdPC0iRnN0IgogICAgY29sbmFtZXMoZGYpWzE6M108LWNvbmFtZXMKICAgIGRmJHBvcDwtcGFzdGUwKHBvcDEsIi52cy4iLHBvcDIpCiAgICBkZiRjaD1hcy5pbnRlZ2VyKGdzdWIoImNociIsIiIsIGRmJGNocikpCiAgICBkZjwtZGZbb3JkZXIoZGYkY2gpLF0KICAgIGRmJGxvYzwtMTpucm93KGRmKQogICAgZnN0PC1yYmluZChmc3QsIGRmKQp9CmV2ZW5zPC1wYXN0ZTAoImNociIsc2VxKDIsMjYsIGJ5PTIpKQojUGxvdCBGc3QgdmFsdWVzIGFjcm9zcyBHZW5vbWUKZnN0JGNvbG9yPC0iY29sMSIKZnN0JGNvbG9yW2ZzdCRjaHIgJWluJSBldmVuc108LSJjb2wyIgpmc3QkcG9wPC1mYWN0b3IoZnN0JHBvcCwgbGV2ZWxzPXVuaXF1ZShmc3QkcG9wKSkKCiNhZGQgY2hyb21vc29tZSBudW1iZXIKZGY8LWZzdFtmc3QkcG9wPT0iVEI5MS52cy5UQjk2IixdCnJvd3M8LWRhdGEuZnJhbWUoY2hyPTE6MjYpCmZvciAoaSBpbiAxOjI2KXsKICAgIGlmIChpID09MSl7CiAgICAgICAgcm93cyRuW2ldPC1ucm93KGRmW2RmJGNoPT1pLF0pCiAgICAgICAgcm93cyRtaWRkbGVbaV08LS1ucm93KGRmW2RmJGNoPT1pLF0pLzIKICAgIH0KICAgIGlmIChpID4xKXsKICAgICAgICByb3dzJG5baV08LW5yb3coZGZbZGYkY2g9PWksXSkKICAgICAgICByb3dzJG1pZGRsZVtpXTwtc3VtKHJvd3MkblsxOihpLTEpXSkrcm93cyRuW2ldLzIKICAgIH0KfQojCmdncGxvdChmc3QsIGFlcyh4PWxvYywgeT1Gc3QsIGNvbG9yPWNvbG9yKSkrCiAgICBmYWNldF93cmFwKH5wb3AsIG5jb2wgPSAxLCBzdHJpcC5wb3NpdGlvbj0icmlnaHQiKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjIpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmF5NTAiLCJzdGVlbGJsdWUiKSkrCiAgICB0aGVtZV9idygpKwogICAgeWxhYigiRnN0IikreGxhYignR2Vub21lIHBvc2l0aW9uJykrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9cm93cyRtaWRkbGUsIGxhYmVscz0xOjI2KQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvVEJfRnN0X3BhaXJ3aXNlX2NvbXBhcmlzb24ucG5nIiwgd2lkdGggPTE4ICwgaGVpZ2h0ID0gOSwgZHBpPTE1MCkKYGBgCiFbXSguLi9PdXRwdXQvU0ZTL1RCX0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZykgIAoKIyMjIFBhaXJ3aXNlIEZzdCBhbG9uZyBlYWNoIGNocm9tb3NvbWUKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgUGxvdCBGc3QgdmFsdWVzIGFsb25nIGVhY2ggY2hyb21vc29tZQpmc3QkY2hyPC1mYWN0b3IoZnN0JGNociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKZnN0dGI8LWZzdApwbG90czwtbGlzdCgpCmNvbXBhcmU8LXBhc3RlMCh1bmlxdWUoZnN0dGIkcG9wKSkKZm9yIChpIGluIDE6Nil7IAogICAgZnM8LWdzdWIoInZzLiIsIiIsY29tcGFyZVtpXSkKICAgIHBvcHMgPC0gdW5saXN0KHN0cnNwbGl0KGZzLCAiXFwuIikpCiAgICBtYXh5PC1tYXgoZnN0dGIkRnN0W2ZzdHRiJHBvcD09Y29tcGFyZVtpXV0pCiAgICAjIEZzdCB3aXRoIGFjdHVhbCBsaW5lIHRvIGhpZ2hsaWdodCB0aGUgZGlmZmVyZW5jZXMKICAgIHBsb3RzW1tpXV0gPC0gZ2dwbG90KGZzdHRiW2ZzdHRiJHBvcD09Y29tcGFyZVtpXSxdLCBhZXMoeCA9bWlkUG9zLCB5ID1Gc3QgKSkgKyAKICAgICAgICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9IGdyeSxhbHBoYSA9IDAuNCwgc2hhcGUgPSAxKSsKICAgICAgICB0aGVtZV9taW5pbWFsKCkreWxpbSgwLG1heHkrMC4wMikrCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSsKICAgICAgICB5bGFiKCJGc3RcbiIpKyB4bGFiKCIiKSsgCiAgICAgICAgZ2d0aXRsZShwYXN0ZTAocG9wc1sxXSwiIHZzLiIsIHBvcHNbMl0pKSsKICAgICAgICBnZW9tX2xpbmUoY29sb3I9Ymx1LCBzaXplPTAuMikrCiAgICAgICAgZmFjZXRfd3JhcCh+Y2hyLCBuY29sID0gOSkKfQpgYGAKCmBgYHtiYXNofQojVG8gc2F2ZSB0aGUgcGxvdHMsIHJ1biBpbiBSCnBuZyhwYXN0ZTAoIk91dHB1dC9TRlMvVEJfRnN0X21hZjAwX2Noci5wbmciKSwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxOCwgcmVzPTE1MCwgdW5pdHMgPSAiaW4iKSAgCmdyaWQuYXJyYW5nZShwbG90c1tbM11dLCBwbG90c1tbMl1dLCBwbG90c1tbNF1dLCBwbG90c1tbMV1dLHBsb3RzW1s1XV0scGxvdHNbWzZdXSwgbmNvbD0zKSAgCmRldi5vZmYoKSAgCmBgYAoKIVtdKC4uL091dHB1dC9TRlMvVEJfRnN0X21hZjAwX2Noci5wbmcpICAKCgojIyMgUGFpcndpc2UgRnN0IG1hdHJpeApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSAgCiMjIENvbnRpbnVlZCBmcm9tIHRoZSBhYm92ZQpwb3BzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IikKY29tYjwtdChjb21ibihwb3BzLDIpKQoKIyMgUGxvdCBhdmVyYWdlIGZzdCBpbiBhIGhlYXRtYXAKY29tcGFyZTwtdW5pcXVlKGZzdCRwb3ApCnBhaXJmc3Q8LWRhdGEuZnJhbWUobWF0cml4KG5jb2w9NCwgbnJvdz00KSwgcm93Lm5hbWVzPXBvcHMpCmNvbG5hbWVzKHBhaXJmc3QpPC1wb3BzCmZvciAoaSBpbiAxOjYpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1mc3RbZnN0JHBvcD09Y29tcGFyZVtpXSxdCiAgICBwYWlyZnN0W3BvcDEscG9wMl08LW1lYW4oZGYkRnN0LCBuYS5ybT1UKQp9CndyaXRlLmNzdihwYWlyZnN0LCIuLi9PdXRwdXQvU0ZTL1RCX3BhaXJ3aXNlRnN0X21hdHJpeC5jc3YiKQoKI3BhaXJmc3Q8LXJlYWQuY3N2KCIuLi9PdXRwdXQvU0ZTL1RCX3BhaXJ3aXNlRnN0X21hdHJpeC5jc3YiLCByb3cubmFtZXMgPSAxKQoKZGY8LXBhaXJmc3QKZGlhZyhkZik8LTAKZGYkcG9wPC1yb3duYW1lcyhkZikKZGZtPC1tZWx0KGRmLG5hLnJtPVQsIGlkLnZhcnM9J3BvcCcpCiNOQSB0byBkaWFnb25hbApkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKZGZtJHBvcDwtZmFjdG9yKGRmbSRwb3AsIGxldmVscz1wb3BzKQpkZm0kdmFsdWU8LXJvdW5kKGRmbSR2YWx1ZSwgNCkKZ2dwbG90KGRhdGEgPSBkZm0sIGFlcyhwb3AsIHZhcmlhYmxlLCBmaWxsID0gdmFsdWUpKSsKICAgIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWMoIndoaXRlIiwgIiMwQzU0RkYiKSwgbGltaXRzPWMoMCwgKG1heChkZm0kdmFsdWUsIG5hLnJtPVQpKzAuMDA1KSksbmEudmFsdWU9ImdyYXk4MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iRnN0IikrCiAgICB0aGVtZV9taW5pbWFsKCkrIHhsYWIoIiIpK3lsYWIoIiIpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCB2anVzdCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSkpKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkrCiAgICBjb29yZF9maXhlZCgpKwogICAgZ2VvbV90ZXh0KGFlcyhwb3AsIHZhcmlhYmxlLCBsYWJlbCA9IHZhbHVlKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNSkKZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9wYWlyd2lzZUZzdF9UQi5wbmciKSwgd2lkdGggPSA1LCBoZWlnaHQgPSA1LCBkcGk9MTUwKQpgYGAKIVtdKC4uL091dHB1dC9TRlMvcGFpcndpc2VGc3RfVEIucG5nKXt3aWR0aD01MCV9ICAKCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFBsb3QgRnN0IGluIGEgYmFyIHBsb3Qgb3JkZXJlZCBhbmQgY29sb3JlZCBpbiB0aGUgc2FtZSB3YXkgYXMgRnN0L1BpIHNodWZmbGUgcmVzdWx0cyAoU2h1ZmZsaW5nX3BpLmZzdC50ZWhhdC5SbWQpCmZzdHM8LWRmbVshaXMubmEoZGZtJHZhbHVlKSxdCmZzdHMkY29tcDwtcGFzdGUwKGZzdHMkcG9wLCJfIixmc3RzJHZhcmlhYmxlKQoKI3NldCB0aGUgY29sb3JzCiNkaXYxPC1kaXZlcmdpbmdfaGNsKDYsIHBhbGV0dGU9IkJsdWUtUmVkIikKI2RpdjI8LXJldihkaXYxKQojbmFtZXMoZGl2Mik8LWMoIlBXUzk2X1BXUzA3IiwiUFdTMDdfUFdTMTciLCJQV1M5MV9QV1M5NiIsICJQV1M5MV9QV1MwNyIsICJQV1M5MV9QV1MxNyIsIlBXUzk2X1BXUzE3IikKZnN0czwtZnN0c1tvcmRlcihmc3RzJHZhbHVlLCBkZWNyZWFzaW5nID0gVCksXQpmc3RzJGNvbXA8LWZhY3Rvcihmc3RzJGNvbXAsIGxldmVscz1wYXN0ZTAodW5pcXVlKGZzdHMkY29tcCkpKQoKZ2dwbG90KGZzdHMsIGFlcyh4PWNvbXAsIHk9dmFsdWUsIGZpbGw9Y29tcCkpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGRpdjEpKwogICAgeGxhYignJykreWxhYignRnN0JykrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L1RCX1BhaXJ3aXNlRnN0X29yZGVyZWQucG5nIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLjgsIGRwaT0zMDAgKQoKI0ZzdCBvdmVyIHRpbWUKZnN0czI8LWZzdHNbZnN0cyRjb21wICVpbiUgYygiVEI5MV9UQjk2IiwiVEI5Nl9UQjA2IiwiVEIwNl9UQjE3IiksXQpmc3RzMiR0aW1lPC0xCmZzdHMyJHRpbWVbZnN0czIkY29tcD09IlRCOTZfVEIwNiJdPC0yCmZzdHMyJHRpbWVbZnN0czIkY29tcD09IlRCMDZfVEIxNyJdPC0zCmZzdHMyPC1mc3RzMltvcmRlcihmc3RzMiR0aW1lKSxdCmdncGxvdChmc3RzMiwgYWVzKHg9dGltZSwgeT12YWx1ZSkpKwogICAgZ2VvbV9wb2ludChzaXplPTMsIGNvbG9yPSJzdGVlbGJsdWUiKSsKICAgIGdlb21fcGF0aCggYWVzKHg9dGltZSwgeT12YWx1ZSksY29sb3I9InN0ZWVsYmx1ZSIpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjE5OTEtMTk5NiIsICIxOTk2LTIwMDYiLCIyMDA2LTIwMTciKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV9UQi5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgpmc3RzJHNlcmllczwtIjE5OTEtMjAwNywgMTk5MS0yMDE3Igpmc3RzJHNlcmllc1tmc3RzJGNvbXAgJWluJSBjKCJUQjkxX1RCOTYiLCJUQjk2X1RCMDYiLCJUQjA2X1RCMTciKV08LSIxOTkxLTE5OTYsIDE5OTYtMjAwNywgMjAwNy0yMDE3Igpmc3RzJHNlcmllc1tmc3RzJGNvbXAgPT0iVEI5Nl9UQjE3Il08LSIxOTk2LTIwMTciCmZzdHMkdGltZTwtMQpmc3RzJHRpbWVbZnN0cyR2YXJpYWJsZT09IlRCMTciXTwtMwpmc3RzJHRpbWVbZnN0cyR2YXJpYWJsZT09IlRCMDYiXTwtMgojc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKZnN0czwtZnN0c1tvcmRlcihmc3RzJHRpbWUpLF0KZ2dwbG90KGZzdHMsIGFlcyh4PXRpbWUsIHk9dmFsdWUsIGNvbG9yPXNlcmllcykpKwogICAgZ2VvbV9wb2ludChzaXplPTMpKwogICAgZ2VvbV9wYXRoKCkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHMpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjE5OTEtMTk5NiIsICJ+MjAwNyIsIn4yMDE3IikpKwogICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9Gc3QvRnN0X292ZXJUaW1lX1RCX2FsbENvbXBhcmlzb24ucG5nIiwgd2lkdGggPSA2LCBoZWlnaHQgPSAyLjgsIGRwaT0zMDAgKQoKIyBwbG90IGJvdGggUFdTIGFuZCBUQiB0b2dldGhlcgoKZnN0UDIkcG9wPC0iUFdTIgpmc3RzMiRwb3A8LSJUQiIKZnN0UFQ8LXJiaW5kKGZzdFAyLCBmc3RzMikKCmdncGxvdChmc3RQVCwgYWVzKHg9dGltZSwgeT12YWx1ZSwgY29sb3I9cG9wKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MykrCiAgICBnZW9tX3BhdGgoIGFlcyh4PXRpbWUsIHk9dmFsdWUpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sc1tjKDIsMSldKSsKICAgIHRoZW1lX2NsYXNzaWMoKSt5bGFiKCJGc3QiKSt4bGFiKCIiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxLDIsMyksIGxhYmVscz1jKCIxOTkxLTE5OTYiLCAiMTk5Ni0yMDA2IiwiMjAwNi0yMDE3IikpKwogICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9Gc3QvRnN0X292ZXJUaW1lX1BXU19UQi5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgpgYGAKCiFbXSguLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV9UQi5wbmcpe3dpZHRoPTUwJV19CgoKCiFbXSguLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV9UQl9hbGxDb21wYXJpc29uLnBuZyl7d2lkdGg9NjQlXQoKCiMjIyBNZWFuIHBhaXJzaWUgRnN0IHBlciBjaHJvbW9zb21lIApgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSAgCiMgUGxvdCBtZWFuIEZzdCBvZiBlYWNoIGNocm9tb3NtZQpGc3Q8LWRhdGEuZnJhbWUoKQpmb3IgKGogaW4gMToyNil7CiAgICBmc3QuY2g8LWZzdFtmc3QkY2g9PWosXQogICAgcGFpcmNoPC1kYXRhLmZyYW1lKG1hdHJpeChuY29sPTQsIG5yb3c9NCksIHJvdy5uYW1lcz1wb3BzKQogICAgY29sbmFtZXMocGFpcmNoKTwtcG9wcwogICAgZm9yIChpIGluIDE6Nil7CiAgICAgICAgcG9wMTwtY29tYltpLDFdCiAgICAgICAgcG9wMjwtY29tYltpLDJdCiAgICAgICAgZGY8LWZzdC5jaFtmc3QuY2gkcG9wPT1jb21wYXJlW2ldLF0KICAgICAgICBwYWlyY2hbcG9wMSxwb3AyXTwtbWVhbihkZiRGc3QsIG5hLnJtPVQpCiAgICB9CiAgICBkaWFnKHBhaXJjaCk8LTAKICAgIHBhaXJjaCRwb3A8LXJvd25hbWVzKHBhaXJjaCkKICAgIGRmbTwtbWVsdChwYWlyY2gsbmEucm09VCwgaWQudmFycz0ncG9wJykKICAgIAogICAgI05BIHRvIGRpYWdvbmFsCiAgICBkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKICAgIGRmbSRwb3A8LWZhY3RvcihkZm0kcG9wLCBsZXZlbHM9cG9wcykKICAgIGRmbSR2YWx1ZTwtcm91bmQoZGZtJHZhbHVlLCA0KQogICAgZGZtJGNocjwtagogICAgRnN0PC1yYmluZChGc3QsIGRmbSkKICAgIAp9CkZzdCRpZDwtcGFzdGUwKEZzdCRwb3AsIiB2cy4iLEZzdCR2YXJpYWJsZSkKRnN0PC1Gc3RbIWlzLm5hKEZzdCR2YWx1ZSksXQpnZ3Bsb3QoRnN0LCBhZXMoeD1jaHIsIHk9dmFsdWUsY29sb3I9aWQpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fcGF0aChzdGF0PSJpZGVudGl0eSIpKwogICAgdGhlbWVfbWluaW1hbCgpK3lsYWIoIkZzdCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz0xOjI2LCBsYWJlbHMgPSAxOjI2KSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvVEJfRnN0X2J5Q2hyb21vc29tZV9kb3RwbG90LnBuZyIsIHdpZHRoID0gMTMsIGhlaWdodD02LjUsIGRwaT0xNTApCmBgYAoKIVtUQiBtZWFuIEZzdCBwZXIgY2hyb21vc29tZV0oLi4vT3V0cHV0L1NGUy9UQl9Gc3RfYnlDaHJvbW9zb21lX2RvdHBsb3QucG5nKQoKPGJyPgoKIyMgU2l0a2EgU291bmQgIAojIyMgUGFpcndpc2UgRnN0IGFsb25nIHRoZSBnZW5vbWUgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cgpwb3BzPC1jKCJTUzk2IiwiU1MwNiIsIlNTMTciKQpjb21iPC10KGNvbWJuKHBvcHMsMikpCgpmc3Q8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgZGY8LXJlYWQuZGVsaW0ocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mc3RfIixwb3AxLCJfIixwb3AyLCJfNTBrV2luZG93X21hZjAwIikpCiAgICBjb25hbWVzPC1jb2xuYW1lcyhkZilbMjo0XQogICAgY29sbmFtZXMoZGYpWzRdPC0iRnN0IgogICAgY29sbmFtZXMoZGYpWzE6M108LWNvbmFtZXMKICAgIGRmJHBvcDwtcGFzdGUwKHBvcDEsIi52cy4iLHBvcDIpCiAgICBkZiRjaD1hcy5pbnRlZ2VyKGdzdWIoImNociIsIiIsIGRmJGNocikpCiAgICBkZjwtZGZbb3JkZXIoZGYkY2gpLF0KICAgIGRmJGxvYzwtMTpucm93KGRmKQogICAgZnN0PC1yYmluZChmc3QsIGRmKQp9CgpldmVuczwtcGFzdGUwKCJjaHIiLHNlcSgyLDI2LCBieT0yKSkKI1Bsb3QgRnN0IHZhbHVlcyBhY3Jvc3MgR2Vub21lCmZzdCRjb2xvcjwtImNvbDEiCmZzdCRjb2xvcltmc3QkY2hyICVpbiUgZXZlbnNdPC0iY29sMiIKZnN0JHBvcDwtZmFjdG9yKGZzdCRwb3AsIGxldmVscz11bmlxdWUoZnN0JHBvcCkpCgojYWRkIGNocm9tb3NvbWUgbnVtYmVyCmRmPC1mc3RbZnN0JHBvcD09IlNTOTYudnMuU1MwNiIsXQpyb3dzPC1kYXRhLmZyYW1lKGNocj0xOjI2KQpmb3IgKGkgaW4gMToyNil7CiAgICBpZiAoaSA9PTEpewogICAgICAgIHJvd3MkbltpXTwtbnJvdyhkZltkZiRjaD09aSxdKQogICAgICAgIHJvd3MkbWlkZGxlW2ldPC0tbnJvdyhkZltkZiRjaD09aSxdKS8yCiAgICB9CiAgICBpZiAoaSA+MSl7CiAgICAgICAgcm93cyRuW2ldPC1ucm93KGRmW2RmJGNoPT1pLF0pCiAgICAgICAgcm93cyRtaWRkbGVbaV08LXN1bShyb3dzJG5bMTooaS0xKV0pK3Jvd3MkbltpXS8yCiAgICB9Cn0KIwpnZ3Bsb3QoZnN0LCBhZXMoeD1sb2MsIHk9RnN0LCBjb2xvcj1jb2xvcikpKwogICAgZmFjZXRfd3JhcCh+cG9wLCBuY29sID0gMSwgc3RyaXAucG9zaXRpb249InJpZ2h0IikrCiAgICBnZW9tX3BvaW50KHNpemU9MC4yKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JheTUwIiwic3RlZWxibHVlIikpKwogICAgdGhlbWVfYncoKSsKICAgIHlsYWIoIkZzdCIpK3hsYWIoJ0dlbm9tZSBwb3NpdGlvbicpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXJvd3MkbWlkZGxlLCBsYWJlbHM9MToyNikKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1NTX0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZyIsIHdpZHRoID0gMTYsIGhlaWdodCA9IDcsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1NGUy9TU19Gc3RfcGFpcndpc2VfY29tcGFyaXNvbi5wbmcpICAKICAKICAgCiMjIyBQYWlyd2lzZSBGc3QgYWxvbmcgZWFjaCBjaHJvbW9zb21lCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9CiMjIFBsb3QgRnN0IHZhbHVlcyBhbG9uZyBlYWNoIGNocm9tb3NvbWUKZnN0JGNocjwtZmFjdG9yKGZzdCRjaHIsIGxldmVscz1wYXN0ZTAoImNociIsMToyNikpCmZzdHNzPC1mc3QKcGxvdHM8LWxpc3QoKQpjb21wYXJlPC1wYXN0ZTAodW5pcXVlKGZzdHNzJHBvcCkpCmZvciAoaSBpbiAxOjMpeyAKICAgIGZzPC1nc3ViKCJ2cy4iLCIiLGNvbXBhcmVbaV0pCiAgICBwb3BzIDwtIHVubGlzdChzdHJzcGxpdChmcywgIlxcLiIpKQogICAgbWF4eTwtbWF4KGZzdHNzJEZzdFtmc3RzcyRwb3A9PWNvbXBhcmVbaV1dKQogICAgIyBGc3Qgd2l0aCBhY3R1YWwgbGluZSB0byBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2VzCiAgICBwbG90c1tbaV1dIDwtIGdncGxvdChmc3Rzc1tmc3RzcyRwb3A9PWNvbXBhcmVbaV0sXSwgYWVzKHggPW1pZFBvcywgeSA9RnN0ICkpICsgCiAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMSwgY29sb3IgPSBncnksYWxwaGEgPSAwLjQsIHNoYXBlID0gMSkrCiAgICAgICAgdGhlbWVfbWluaW1hbCgpK3lsaW0oMCxtYXh5KzAuMDIpKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkrCiAgICAgICAgeWxhYigiRnN0XG4iKSsgeGxhYigiIikrIAogICAgICAgIGdndGl0bGUocGFzdGUwKHBvcHNbMV0sIiB2cy4iLCBwb3BzWzJdKSkrCiAgICAgICAgZ2VvbV9saW5lKGNvbG9yPWJsdSwgc2l6ZT0wLjIpKwogICAgICAgIGZhY2V0X3dyYXAofmNociwgbmNvbCA9IDkpCn0KCntwbmcocGFzdGUwKCJPdXRwdXQvU0ZTL1NTX0ZzdF9tYWYwMF9jaHIucG5nIiksIGhlaWdodCA9IDQsIHdpZHRoID0gMTgsIHJlcz0xNTAsIHVuaXRzID0gImluIikgIApncmlkLmFycmFuZ2UocGxvdHNbWzFdXSwgcGxvdHNbWzJdXSwgcGxvdHNbWzNdXSwgbmNvbD0zKSAgCmRldi5vZmYoKSAgfQpgYGAKCiFbXSguLi9PdXRwdXQvU0ZTL1NTX0ZzdF9tYWYwMF9jaHIucG5nKSAgCiAgCiMjIyBQYWlyd2lzZSBGc3QgbWF0cml4CmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIENvbnRpbnVlZCBmcm9tIHRoZSBhYm92ZQpwb3BzPC1jKCJTUzk2IiwiU1MwNiIsIlNTMTciKQpjb21iPC10KGNvbWJuKHBvcHMsMikpCgojIyBQbG90IGF2ZXJhZ2UgZnN0IGluIGEgaGVhdG1hcApjb21wYXJlPC11bmlxdWUoZnN0JHBvcCkKcGFpcmZzdDwtZGF0YS5mcmFtZShtYXRyaXgobmNvbD0zLCBucm93PTMpLCByb3cubmFtZXM9cG9wcykKY29sbmFtZXMocGFpcmZzdCk8LXBvcHMKZm9yIChpIGluIDE6Myl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgZGY8LWZzdFtmc3QkcG9wPT1jb21wYXJlW2ldLF0KICAgIHBhaXJmc3RbcG9wMSxwb3AyXTwtbWVhbihkZiRGc3QsIG5hLnJtPVQpCn0Kd3JpdGUuY3N2KHBhaXJmc3QsIi4uL091dHB1dC9TRlMvU1NfcGFpcndpc2VGc3RfbWF0cml4LmNzdiIpCgpwYWlyZnN0PC1yZWFkLmNzdigiLi4vT3V0cHV0L1NGUy9TU19wYWlyd2lzZUZzdF9tYXRyaXguY3N2Iiwgcm93Lm5hbWVzID0gMSkKZGY8LXBhaXJmc3QKZGlhZyhkZik8LTAKZGYkcG9wPC1yb3duYW1lcyhkZikKZGZtPC1tZWx0KGRmLG5hLnJtPVQsIGlkLnZhcnM9J3BvcCcpCiNOQSB0byBkaWFnb25hbApkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKZGZtJHBvcDwtZmFjdG9yKGRmbSRwb3AsIGxldmVscz1wb3BzKQpkZm0kdmFsdWU8LXJvdW5kKGRmbSR2YWx1ZSwgNCkKZ2dwbG90KGRhdGEgPSBkZm0sIGFlcyhwb3AsIHZhcmlhYmxlLCBmaWxsID0gdmFsdWUpKSsKICAgIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWMoIndoaXRlIiwgIiMwQzU0RkYiKSwgbGltaXRzPWMoMCwgKG1heChkZm0kdmFsdWUsIG5hLnJtPVQpKzAuMDA1KSksbmEudmFsdWU9ImdyYXk4MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iRnN0IikrCiAgICB0aGVtZV9taW5pbWFsKCkrIHhsYWIoIiIpK3lsYWIoIiIpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCB2anVzdCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSkpKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkrCiAgICBjb29yZF9maXhlZCgpKwogICAgZ2VvbV90ZXh0KGFlcyhwb3AsIHZhcmlhYmxlLCBsYWJlbCA9IHZhbHVlKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNSkKZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9wYWlyd2lzZUZzdF9TUy5wbmciKSwgd2lkdGggPSA1LCBoZWlnaHQgPSA1LCBkcGk9MTUwKQpgYGAKIVtdKC4uL091dHB1dC9TRlMvcGFpcndpc2VGc3RfU1MucG5nKXt3aWR0aD02MCV9ICAKCgoKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgUGxvdCBGc3QgaW4gYSBiYXIgcGxvdCBvcmRlcmVkIGFuZCBjb2xvcmVkIGluIHRoZSBzYW1lIHdheSBhcyBGc3QvUGkgc2h1ZmZsZSByZXN1bHRzIChTaHVmZmxpbmdfcGkuZnN0LnRlaGF0LlJtZCkKZnN0czwtZGZtWyFpcy5uYShkZm0kdmFsdWUpLF0KZnN0cyRjb21wPC1wYXN0ZTAoZnN0cyRwb3AsIl8iLGZzdHMkdmFyaWFibGUpCgojc2V0IHRoZSBjb2xvcnMKI2RpdjE8LWRpdmVyZ2luZ19oY2woNiwgcGFsZXR0ZT0iQmx1ZS1SZWQiKQojZGl2MjwtcmV2KGRpdjEpCiNuYW1lcyhkaXYyKTwtYygiUFdTOTZfUFdTMDciLCJQV1MwN19QV1MxNyIsIlBXUzkxX1BXUzk2IiwgIlBXUzkxX1BXUzA3IiwgIlBXUzkxX1BXUzE3IiwiUFdTOTZfUFdTMTciKQpmc3RzPC1mc3RzW29yZGVyKGZzdHMkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCmZzdHMkY29tcDwtZmFjdG9yKGZzdHMkY29tcCwgbGV2ZWxzPXBhc3RlMCh1bmlxdWUoZnN0cyRjb21wKSkpCgpnZ3Bsb3QoZnN0cywgYWVzKHg9Y29tcCwgeT12YWx1ZSwgZmlsbD1jb21wKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZGl2MSkrCiAgICB4bGFiKCcnKSt5bGFiKCdGc3QnKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9Gc3QvVEJfUGFpcndpc2VGc3Rfb3JkZXJlZC5wbmciLCB3aWR0aCA9IDMuNCwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCiNGc3Qgb3ZlciB0aW1lCmZzdHMyPC1mc3RzW2ZzdHMkY29tcCAlaW4lIGMoIlNTOTZfU1MwNiIsIlNTMDZfU1MxNyIpLF0KZnN0czIkdGltZTwtMQpmc3RzMiR0aW1lW2ZzdHMyJGNvbXA9PSJTUzk2X1NTMDYiXTwtMgpmc3RzMiR0aW1lW2ZzdHMyJGNvbXA9PSJTUzA2X1NTMTciXTwtMwpmc3RzMjwtZnN0czJbb3JkZXIoZnN0czIkdGltZSksXQpnZ3Bsb3QoZnN0czIsIGFlcyh4PXRpbWUsIHk9dmFsdWUpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zLCBjb2xvcj0ic3RlZWxibHVlIikrCiAgICBnZW9tX3BhdGgoIGFlcyh4PXRpbWUsIHk9dmFsdWUpLGNvbG9yPSJzdGVlbGJsdWUiKSsKICAgIHRoZW1lX2NsYXNzaWMoKSt5bGFiKCJGc3QiKSt4bGFiKCIiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxLDIsMyksIGxhYmVscz1jKCIxOTkxLTE5OTYiLCAiMTk5Ni0yMDA2IiwiMjAwNi0yMDE3IikpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfU1MucG5nIiwgd2lkdGggPSAzLjUsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgpmc3RzJHNlcmllczwtIjE5OTEtMjAwNywgMTk5MS0yMDE3Igpmc3RzJHNlcmllc1tmc3RzJGNvbXAgPT0iU1M5Nl9TUzE3Il08LSIxOTk2LTIwMTciCmZzdHMkdGltZTwtMQpmc3RzJHRpbWVbZnN0cyR2YXJpYWJsZT09IlNTMTciXTwtMwpmc3RzJHRpbWVbZnN0cyR2YXJpYWJsZT09IlNTMDYiXTwtMgojc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKZnN0czwtZnN0c1tvcmRlcihmc3RzJHRpbWUpLF0KZ2dwbG90KGZzdHMsIGFlcyh4PXRpbWUsIHk9dmFsdWUsIGNvbG9yPXNlcmllcykpKwogICAgZ2VvbV9wb2ludChzaXplPTMpKwogICAgZ2VvbV9wYXRoKCkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHMpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjE5OTEtMTk5NiIsICJ+MjAwNyIsIn4yMDE3IikpKwogICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9Gc3QvRnN0X292ZXJUaW1lX1NTX2FsbENvbXBhcmlzb24ucG5nIiwgd2lkdGggPSA2LCBoZWlnaHQgPSAyLjgsIGRwaT0zMDAgKQoKCiMgcGxvdCBhbGwgMyBwb3BzIHRvZ2V0aGVyCgpmc3RzMiRwb3A8LSJTUyIKCmZzdFBTVDwtcmJpbmQoZnN0UFQsIGZzdHMyKQoKZ2dwbG90KGZzdFBTVCwgYWVzKHg9dGltZSwgeT12YWx1ZSwgY29sb3I9cG9wKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MykrCiAgICBnZW9tX3BhdGgoIGFlcyh4PXRpbWUsIHk9dmFsdWUpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sc1tjKDIsMSwzKV0pKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjE5OTEtMTk5NiIsICIxOTk2LTIwMDYiLCIyMDA2LTIwMTciKSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfM1BvcHMucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAyLjgsIGRwaT0zMDAgKQoKYGBgCiFbXSguLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV8zUG9wcy5wbmcpe3dpZHRoPTYwJX0KCgojIyMgTWVhbiBwYWlyc2llIEZzdCBwZXIgY2hyb21vc29tZSAgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9ICAKIyBQbG90IG1lYW4gRnN0IG9mIGVhY2ggY2hyb21vc29tZXMKRnN0PC1kYXRhLmZyYW1lKCkKZm9yIChqIGluIDE6MjYpewogICAgZnN0LmNoPC1mc3RbZnN0JGNoPT1qLF0KICAgIHBhaXJjaDwtZGF0YS5mcmFtZShtYXRyaXgobmNvbD0zLCBucm93PTMpLCByb3cubmFtZXM9cG9wcykKICAgIGNvbG5hbWVzKHBhaXJjaCk8LXBvcHMKICAgIGZvciAoaSBpbiAxOjMpewogICAgICAgIHBvcDE8LWNvbWJbaSwxXQogICAgICAgIHBvcDI8LWNvbWJbaSwyXQogICAgICAgIGRmPC1mc3QuY2hbZnN0LmNoJHBvcD09Y29tcGFyZVtpXSxdCiAgICAgICAgcGFpcmNoW3BvcDEscG9wMl08LW1lYW4oZGYkRnN0LCBuYS5ybT1UKQogICAgfQogICAgZGlhZyhwYWlyY2gpPC0wCiAgICBwYWlyY2gkcG9wPC1yb3duYW1lcyhwYWlyY2gpCiAgICBkZm08LW1lbHQocGFpcmNoLG5hLnJtPVQsIGlkLnZhcnM9J3BvcCcpCiAgICAKICAgICNOQSB0byBkaWFnb25hbAogICAgZGZtJHZhbHVlW2RmbSR2YWx1ZT09MF08LU5BCiAgICBkZm0kcG9wPC1mYWN0b3IoZGZtJHBvcCwgbGV2ZWxzPXBvcHMpCiAgICBkZm0kdmFsdWU8LXJvdW5kKGRmbSR2YWx1ZSwgNCkKICAgIGRmbSRjaHI8LWoKICAgIEZzdDwtcmJpbmQoRnN0LCBkZm0pCiAgICAKfQpGc3QkaWQ8LXBhc3RlMChGc3QkcG9wLCIgdnMuIixGc3QkdmFyaWFibGUpCkZzdDwtRnN0WyFpcy5uYShGc3QkdmFsdWUpLF0KZ2dwbG90KEZzdCwgYWVzKHg9Y2hyLCB5PXZhbHVlLGNvbG9yPWlkKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBnZW9tX3BhdGgoc3RhdD0iaWRlbnRpdHkiKSsKICAgIHRoZW1lX21pbmltYWwoKSt5bGFiKCJGc3QiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9MToyNiwgbGFiZWxzID0gMToyNikrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1NTX0ZzdF9ieUNocm9tb3NvbWVfZG90cGxvdC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodD00LjUsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1NGUy9TU19Gc3RfYnlDaHJvbW9zb21lX2RvdHBsb3QucG5nKQoKCgoKIyMgMjAxNyBQb3B1bGF0aW9ucwoKIyMjIFBhaXJpd3NlIEZzdCBhbG9uZyB0aGUgZ2Vub21lICAKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wc248LXJlYWQuY3N2KCIuLi9EYXRhL1NhbXBsZV9tZXRhZGF0YV84OTJwb3BzLmNzdiIpCnBvcHM8LXVuaXF1ZShwb3BzbiRQb3B1bGF0aW9uLlllYXIpCnkxNzwtcG9wc1tncmVwKCIxNyIscG9wcyldCgpjb21iPC1jb21ibih5MTcsIDIpCmNvbWI8LXQoY29tYikKCiNZZWFyMjAxNwpmc3QxNzwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOiBucm93KGNvbWIpKXsKICAgIHBvcDE8LWNvbWJbaSwxXQogICAgcG9wMjwtY29tYltpLDJdCiAgICBkZjwtcmVhZC5kZWxpbShwYXN0ZTAoIi4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tVkNGLzJEL2ZzdF9mb2xkZWRfIixwb3AxLCJfIixwb3AyLCJfNTBrV2luZG93X21hZjAwIikpCiAgICBjb25hbWVzPC1jb2xuYW1lcyhkZilbMjo0XQogICAgY29sbmFtZXMoZGYpWzRdPC0iRnN0IgogICAgY29sbmFtZXMoZGYpWzE6M108LWNvbmFtZXMKICAgIGRmJHBvcDwtcGFzdGUwKHBvcDEsIi52cy4iLHBvcDIpCiAgICBkZiRjaD1hcy5pbnRlZ2VyKGdzdWIoImNociIsIiIsIGRmJGNocikpCiAgICBkZjwtZGZbb3JkZXIoZGYkY2gpLF0KICAgIGRmJGxvYzwtMTpucm93KGRmKQogICAgZnN0MTc8LXJiaW5kKGZzdDE3LCBkZikKfQoKd3JpdGUuY3N2KGZzdDE3LCIuLi9PdXRwdXQvU0ZTL0ZzdF93aW5kb3dfeWVhcjIwMTdfYWxscG9wcy5jc3YiKQoKZnN0MTckY2g8LWFzLmludGVnZXIoZ3N1YigiY2hyIiwiIixmc3QxNyRjaHIpKQpmc3QxNzwtZnN0MTdbb3JkZXIoZnN0MTckY2gsIGZzdDE3JG1pZFBvcyksXQpmc3QxNyRjaHI8LWZhY3Rvcihmc3QxNyRjaHIsIGxldmVscz1wYXN0ZTAoImNociIsMToyNikpCgpwYWlyczwtdW5pcXVlKGZzdDE3JHBvcCkKcGxvdHM8LWxpc3QoKQpmb3IgKGkgaW4gMTpsZW5ndGgocGFpcnMpKXsgCiAgICBmczwtZ3N1YigiLnZzIiwiIixwYWlyc1tpXSkKICAgIHBvcHMgPC0gdW5saXN0KHN0cnNwbGl0KGZzLCAiXFwuIikpCiAgICAjIEZzdCB3aXRoIGFjdHVhbCBsaW5lIHRvIGhpZ2hsaWdodCB0aGUgZGlmZmVyZW5jZXMKICAgIGRmPC1mc3QxN1tmc3QxNyRwb3A9PXBhaXJzW2ldLF0KICAgIHBsb3RzW1tpXV0gPC0gZ2dwbG90KGRmLCBhZXMoeCA9bWlkUG9zLCB5ID0gRnN0KSkgKyAKICAgICAgICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9ICJncmF5IixhbHBoYSA9IDAuNCwgc2hhcGUgPSAxKSsKICAgICAgICB0aGVtZV9taW5pbWFsKCkrCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSsKICAgICAgICB5bGFiKCJGc3RcbiIpKyB4bGFiKCIiKSsgCiAgICAgICAgZ2d0aXRsZShwYXN0ZTAocG9wc1sxXSwiIHZzLiIsIHBvcHNbMl0pKSsKICAgICAgICBnZW9tX2xpbmUoY29sb3I9InN0ZWVsYmx1ZSIsIHNpemU9MC4yKSsKICAgICAgICBmYWNldF93cmFwKH5jaHIsIG5jb2wgPSA5KQp9CgojU2FtZSB5LWF4aXMKcGxvdHMyPC1saXN0KCkKI1RCIHlsaW09MC44CiNub25UQiAwLjYKZm9yIChpIGluIDE6bGVuZ3RoKHBhaXJzKSl7IAogICAgZnM8LWdzdWIoIi52cyIsIiIscGFpcnNbaV0pCiAgICBwb3BzIDwtIHVubGlzdChzdHJzcGxpdChmcywgIlxcLiIpKQogICAgIyBGc3Qgd2l0aCBhY3R1YWwgbGluZSB0byBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2VzCiAgICBkZjwtZnN0MTdbZnN0MTckcG9wPT1wYWlyc1tpXSxdCiAgICBpZiAoaSAlaW4lIGMoNCw4LDExLDEzLDE1KSkgeW1heD0wLjgKICAgIGVsc2UgeW1heD0wLjYKICAgIHBsb3RzMltbaV1dIDwtIGdncGxvdChkZiwgYWVzKHggPW1pZFBvcywgeSA9IEZzdCkpICsgCiAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMSwgY29sb3IgPSAiZ3JheSIsYWxwaGEgPSAwLjQsIHNoYXBlID0gMSkrCiAgICAgICAgdGhlbWVfbWluaW1hbCgpK3lsaW0oMCx5bWF4KSsKICAgICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpKwogICAgICAgIHlsYWIoIkZzdFxuIikrIHhsYWIoIiIpKyAKICAgICAgICBnZ3RpdGxlKHBhc3RlMChwb3BzWzFdLCIgdnMuIiwgcG9wc1syXSkpKwogICAgICAgIGdlb21fbGluZShjb2xvcj0ic3RlZWxibHVlIiwgc2l6ZT0wLjIpKwogICAgICAgIGZhY2V0X3dyYXAofmNociwgbmNvbCA9IDkpCn0KCmBgYAoKCmBgYHtSfQp7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9ZZWFyMjAxN19Gc3QxLnBuZyIpLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDIwLCByZXM9MTUwLCB1bml0cyA9ICJpbiIpCmRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKHBsb3RzWzE6Nl0sIG5jb2w9MykpCmRldi5vZmYoKX0KCntwbmcocGFzdGUwKCIuLi9PdXRwdXQvU0ZTL1llYXIyMDE3X0ZzdDIucG5nIiksIGhlaWdodCA9IDEyLCB3aWR0aCA9IDIwLCByZXM9MTUwLCB1bml0cyA9ICJpbiIpCmRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKHBsb3RzWzc6MTVdLCBuY29sPTMpKQpkZXYub2ZmKCl9CgojcGxvdCBub24tVEIKe3BuZyhwYXN0ZTAoIi4uL091dHB1dC9TRlMvWWVhcjIwMTdfRnN0X3NhbWVZYXhpcy5wbmciKSwgaGVpZ2h0ID0gMTYsIHdpZHRoID0gMjAsIHJlcz0xNTAsIHVuaXRzID0gImluIikKZG8uY2FsbChncmlkLmFycmFuZ2UsIGMocGxvdHMyW2MoMSwyLDMsNSw2LDcsOSwxMCwxMiwxNCldLCBuY29sPTMpKQpkZXYub2ZmKCl9Cgp7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9ZZWFyMjAxN19Gc3Rfc2FtZVlheGlzMl9UQi5wbmciKSwgaGVpZ2h0ID0gMTIsIHdpZHRoID0gMjAsIHJlcz0xNTAsIHVuaXRzID0gImluIikKZG8uY2FsbChncmlkLmFycmFuZ2UsIGMocGxvdHMyW2MoNCw4LDExLDEzLDE1KV0sIG5jb2w9MykpCmRldi5vZmYoKX0KYGBgCgohW2NvbnRyYXN0IHdpdGhvdXQgVEJdKC4uL091dHB1dC9TRlMvWWVhcjIwMTdfRnN0X3NhbWVZYXhpcy5wbmcpCgohW0NvbnRyYXN0IGFnYWluc3QgVEIgcG9wXSguLi9PdXRwdXQvU0ZTL1llYXIyMDE3X0ZzdF9zYW1lWWF4aXMyX1RCLnBuZykKCgojIyMgUGFpd2lzZSBGc3QgbWF0cml4CgpgYGB7ciBlY2hvPVRSVUUsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI1Bsb3QgcGFpcndpc2UgRnN0IHZhbHVlcwpiY3hjYSA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJCQzE3LnZzLkNBMTciXSksNCkKYmN4cHcgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iQkMxNy52cy5QV1MxNyJdKSw0KQpjYXhwdyA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJDQTE3LnZzLlBXUzE3Il0pLDQpCmJjeHdhIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IkJDMTcudnMuV0ExNyJdKSw0KQpjYXh3YSA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJDQTE3LnZzLldBMTciXSksNCkKYmN4c3MgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iQkMxNy52cy5TUzE3Il0pLDQpCmJjeHRiIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IkJDMTcudnMuVEIxNyJdKSw0KQpzc3h0YiA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJTUzE3LnZzLlRCMTciXSksNCkKY2F4c3MgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iQ0ExNy52cy5TUzE3Il0pLDQpCnB3eHNzIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IlBXUzE3LnZzLlNTMTciXSksNCkKY2F4dGIgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iQ0ExNy52cy5UQjE3Il0pLDQpCnB3eHRiIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IlBXUzE3LnZzLlRCMTciXSksNCkKcHd4d2EgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iUFdTMTcudnMuV0ExNyJdKSw0KQpzc3h3YSA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJTUzE3LnZzLldBMTciXSksNCkKdGJ4d2EgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iVEIxNy52cy5XQTE3Il0pLDQpCgpmc3RfdmVjIDwtIGMoMCxwd3h0Yixzc3h0YixiY3h0Yix0Ynh3YSxjYXh0YiwKICAgICAgICAgICAgIHB3eHRiLDAscHd4c3MsYmN4cHcscHd4d2EsY2F4cHcsCiAgICAgICAgICAgICBzc3h0Yixwd3hzcywwLGJjeHNzLHNzeHdhLGNheHNzLAogICAgICAgICAgICAgYmN4dGIsYmN4cHcsYmN4c3MsMCxiY3h3YSxiY3hjYSwKICAgICAgICAgICAgIHRieHdhLHB3eHdhLHNzeHdhLGJjeHdhLDAsY2F4d2EsCiAgICAgICAgICAgICBjYXh0YixjYXhwdyxjYXhzcyxiY3hjYSxjYXh3YSwwKQoKZnN0X21hdCA9IG1hdHJpeChmc3RfdmVjLCBucm93ID0gNiwgbmNvbCA9IDYpCmNvbG5hbWVzKGZzdF9tYXQpIDwtIGMoIlRCMTciLCJQV1MxNyIsIlNTMTciLCJCQzE3IiwiV0ExNyIsIkNBMTciKQpyb3duYW1lcyhmc3RfbWF0KSA8LSBjKCJUQjE3IiwiUFdTMTciLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikKCmZzdF9tYXRbbG93ZXIudHJpKGZzdF9tYXQsIGRpYWcgPSBGKV08LU5BCndyaXRlLmNzdihmc3RfbWF0LCAiLi4vT3V0cHV0L1NGUy9Gc3RfbWF0cml4XzIwMTdfYWxsLmNzdiIpCgojIE1lbHQgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeAptZWx0ZWRfY29ybWF0IDwtIG1lbHQoZnN0X21hdCwgbmEucm0gPSBUUlVFKQptZWx0ZWRfY29ybWF0W21lbHRlZF9jb3JtYXQ9PTBdPC1OQQojIEhlYXRtYXAKbWVsdGVkX2Nvcm1hdCRjb2xvcjwtImEiCm1lbHRlZF9jb3JtYXQkY29sb3JbbWVsdGVkX2Nvcm1hdCR2YWx1ZT49MC4xXTwtImIiCgpnZ3Bsb3QoZGF0YSA9IG1lbHRlZF9jb3JtYXQsIGFlcyhWYXIyLCBWYXIxLCBmaWxsID0gdmFsdWUpKSsKICAgIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWMoIndoaXRlIiwgImJsdWUiKSwgbGltaXRzPWMoMCwgKG1heChtZWx0ZWRfY29ybWF0JHZhbHVlLCBuYS5ybT1UKSswLjAwNSkpLG5hLnZhbHVlPSJncmF5ODAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9IkZzdCIpKwogICAgdGhlbWVfbWluaW1hbCgpKyB4bGFiKCIiKSt5bGFiKCIiKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgdmp1c3QgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwgaGp1c3QgPSAwLjUpKSsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpKwogICAgY29vcmRfZml4ZWQoKSsKICAgIGdlb21fdGV4dChhZXMoVmFyMiwgVmFyMSwgbGFiZWwgPSB2YWx1ZSwgY29sb3I9Y29sb3IpLCAgc2l6ZSA9IDUpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsICJ3aGl0ZSIpLCBndWlkZT0nbm9uZScpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9Gc3RfbWF0cml4XzIwMTdfYWxsLnBuZyIsIGhlaWdodCA9IDYsIHdpZHRoID0gNiwgZHBpPTE1MCkKYGBgCiFbXSguLi9PdXRwdXQvU0ZTL0ZzdF9tYXRyaXhfMjAxN19hbGwucG5nKXt3aWR0aD03NSV9CgojIyBGc3QgY2hhbmdlIG92ZXIgdGltZSBiZXR3ZWVuIFBXUy9TUy9UQgoKYGBge3IgZWNobz1UUlVFLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9Cgpjb21iPC1kYXRhLmZyYW1lKGE9YygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJTUzk2IiwiU1MwNiIsIlNTMTciKSxiPWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciLCJTUzk2IiwiU1MwNiIsIlNTMTciLCJUQjk2IiwiVEIwNiIsIlRCMTciKSkgCgpmc3RzPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1yZWFkLmRlbGltKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZnN0X2ZvbGRlZF8iLHBvcDEsIl8iLHBvcDIsIl81MGtXaW5kb3dfbWFmMDAiKSkKICAgIGNvbmFtZXM8LWNvbG5hbWVzKGRmKVsyOjRdCiAgICBjb2xuYW1lcyhkZilbNF08LSJGc3QiCiAgICBjb2xuYW1lcyhkZilbMTozXTwtY29uYW1lcwogICAgZGYkcG9wPC1wYXN0ZTAocG9wMSwiLnZzLiIscG9wMikKICAgIGRmJGNoPWFzLmludGVnZXIoZ3N1YigiY2hyIiwiIiwgZGYkY2hyKSkKICAgIGRmPC1kZltvcmRlcihkZiRjaCksXQogICAgZGYkbG9jPC0xOm5yb3coZGYpCiAgICBmc3RzPC1yYmluZChmc3RzLCBkZikKfQp3cml0ZS5jc3YoZnN0cywiLi4vT3V0cHV0L1NGUy9Gc3RfYmV0d2VlblBvcC5jc3YiKQoKcmU8LWFnZ3JlZ2F0ZShmc3RzJEZzdCwgYnk9bGlzdChmc3RzJHBvcCksIG1lYW4sIG5hLnJtPVQpCmNvbXBhPC1zdHJzcGxpdChyZSRHcm91cC4xLCBzcGxpdD0iLnZzLiIpCnJlJHBvcDE8LWxhcHBseShjb21wYSwgIltbIiwgMSkKcmUkcG9wMjwtbGFwcGx5KGNvbXBhLCAiW1siLCAyKQpyZSR5ZWFyIDwtIGFzLm51bWVyaWMoc3RyX2V4dHJhY3QocmUkcG9wMSwgIlswLTldKyIpKQpyZSR5ZWFyW3JlJHllYXI9PTd8cmUkeWVhcj09Nl08LTIwMDYKcmUkeWVhcltyZSR5ZWFyPT05MV08LTE5OTEKcmUkeWVhcltyZSR5ZWFyPT05Nl08LTE5OTYKcmUkeWVhcltyZSR5ZWFyPT0xN108LTIwMTcKcmUkcG9wMTwtc3RyX2V4dHJhY3QocmUkcG9wMSwgIlthQS16Wl0rIikKcmUkcG9wMjwtc3RyX2V4dHJhY3QocmUkcG9wMiwgIlthQS16Wl0rIikKcmUkcG9wczwtcGFzdGUwKHJlJHBvcDEsIi0iLHJlJHBvcDIpCgpnZ3Bsb3QocmUsIGFlcyh4PXllYXIsIHk9eCwgY29sb3I9cG9wcywgZ3JvdXA9cG9wcykpKwogICAgZ2VvbV9wb2ludChwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCBzaXplPTMpKwogICAgZ2VvbV9saW5lKHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSkpKwogICAgeWxhYigiRnN0IikreGxhYigiWWVhciIpKwogICAgdGhlbWVfY2xhc3NpYygpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHNbYygxLDUsNCldKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvRnN0X3NoaWZ0X292ZXJZZWFyc18zcG9wcy5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMsIGRwaT0zMDApCgpgYGAKCiFbXSguLi9PdXRwdXQvU0ZTL0ZzdF9zaGlmdF9vdmVyWWVhcnNfM3BvcHMucG5nKXt3aWR0aD01MCV9CgoKCjxicj4KPGJyPgogIAojIFVzZSBQaXh5IHRvIGNhbGN1bGF0ZSBwaQoKIyMgU3RlcHMKCjEuIENyZWF0ZSBhbGwgc2l0ZXMgKGludmFyaWFudCkgdmNmIGZpbGVzICAKKHNlZSBpbnZhcmlhbnRWQ0ZfUFdTOTEuc2gpCgpgYGB7YmFzaCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQojVXNpbmcgYmNmdG9vbHMgbXBpbGV1cCAoLXIgaXMgdG8gc3BlY2lmeSBjaHJvbW9zb21lKQpiY2Z0b29scyBtcGlsZXVwIC1mIDxyZWZlcmVuY2UuZmE+IC1iIDxiYW1saXN0LnR4dD4gLXIgPFg+IHwgYmNmdG9vbHMgY2FsbCAtbSAtT3ogLWYgR1EgLW8gPG91dHB1dD4KCiNDcmVhdGUgYSBzYW1wbGUgaWQgZmlsZSAocmVxdWlyZWQpCiMgQWRkIHBvcHVsYXRpb24gaW5mbyB0byB0aGUgc2FtcGxlIHNoZWV0CnNlZCAncy8kL1x0UFdTOTEvJyBQV1M5MS50eHQgPnB3czkxcG9wLnR4dAoKI2NoZWNrIHRoZSBzYW1wbGUgbmFtZXMgaW4gdGhlIHZjZiBmaWxlCmJjZnRvb2xzIHF1ZXJ5IC1sIFBXUzkxX2NoMS52Y2YuZ3oKIyBzb21laG93LCBfIHdhcyByZXBsYWNlZCBieSAuCmBgYAoKMi4gIFJlZm9ybWF0IHRoZSBzYW1wbGUgZmlsZSAoJ18nIHdhcyByZXBsYWNlZCBieSAnLicgaW4gdGhlIHByb2Nlc3Mgb2YgbWFraW5nIHZjZiBmaWxlcykgICAKCmBgYHtyIGVjaG89VFJVRX0KcG9wczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQpmb3IgKGkgaW4gMTogbGVuZ3RoKHBvcHMpKXsKICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9waXh5LyIscG9wc1tpXSwiLnR4dCIpKQogICAgZGYkVjE8LWdzdWIoIl8iLCIuIiwgZGYkVjEpCiAgICBkZiRWMjwtcG9wc1tpXQogICAgd3JpdGUudGFibGUoZGYsIHBhc3RlMCgiLi4vRGF0YS9waXh5LyIscG9wc1tpXSwicG9wLnR4dCIpLCBxdW90ZSA9IEYsIGNvbC5uYW1lcz1GLCByb3cubmFtZXMgPSBGLCBzZXA9Ilx0IikKfQoKcG9wczwtYygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIpCmZvciAoaSBpbiAxOiBsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW2ldLCIudHh0IikpCiAgICBkZiRWMTwtZ3N1YigiXyIsIi4iLCBkZiRWMSkKICAgIGRmJFYyPC1wb3BzW2ldCiAgICB3cml0ZS50YWJsZShkZiwgcGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW2ldLCIvIiAscG9wc1tpXSwicG9wLnR4dCIpLCBxdW90ZSA9IEYsIGNvbC5uYW1lcz1GLCByb3cubmFtZXMgPSBGLCBzZXA9Ilx0IikKfQoKcG9wczwtYygiU1M5NiIsIlNTMDYiLCJTUzE3IikKZm9yIChpIGluIDE6IGxlbmd0aChwb3BzKSl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvcG9waW5mby8iLHBvcHNbaV0sIi50eHQiKSkKICAgIGRmJFYxPC1nc3ViKCJfIiwiLiIsIGRmJFYxKQogICAgZGYkVjI8LXBvcHNbaV0KICAgIHdyaXRlLnRhYmxlKGRmLCBwYXN0ZTAoIi4uL0RhdGEvcGl4eS8iLHBvcHNbaV0sIi8iICxwb3BzW2ldLCJwb3AudHh0IiksIHF1b3RlID0gRiwgY29sLm5hbWVzPUYsIHJvdy5uYW1lcyA9IEYsIHNlcD0iXHQiKQp9CnBvcHM8LWMoIkNBMTciLCJCQzE3IiwiV0ExNyIpCmZvciAoaSBpbiAxOiBsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL3BvcGluZm8vIixwb3BzW2ldLCIudHh0IikpCiAgICBkZiRWMTwtZ3N1YigiXyIsIi4iLCBkZiRWMSkKICAgIGRmJFYyPC1wb3BzW2ldCiAgICB3cml0ZS50YWJsZShkZiwgcGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW2ldLCIvIiAscG9wc1tpXSwicG9wLnR4dCIpLCBxdW90ZSA9IEYsIGNvbC5uYW1lcz1GLCByb3cubmFtZXMgPSBGLCBzZXA9Ilx0IikKfQpgYGAKCjMuIFJ1biBQaXh5IChleGFtcGxlOiBQV1M5MSBDaHIxKQpgYGB7YmFzaCBlY2hvPVRSVUV9CiNpbmRleCB0aGUgdmNmLmd6IGZpbGUKdGFiaXggUFdTOTFfY2gxLnZjZi5negoKIyBSdW4gUGl4eSAKI2ZpcnN0IGFjdGl2YXRlIHRoZSBjb25kYSBlbnYgKHB5MzgpIC1ydW5zIG9uIG9sZGVyIFB5dGhvbiAoPD0zLjgpCmNvbmRhIGFjdGl2YXRlIHB5MzgKY2Qgfi9Qcm9qZWN0cy9QYWNIZXJyaW5nL0RhdGEvcGl4eQpwaXh5IC0tc3RhdHMgcGkgLS12Y2YgUFdTOTFfY2gxLnZjZi5neiAtLXBvcHVsYXRpb25zIHB3czkxcG9wLnR4dCAtLXdpbmRvd19zaXplIDEwMDAwIC0tbl9jb3JlIDggLS1vdXRwdXRfcHJlZml4IFBXUzkxX2NoMQoKY29uZGEgZGVhY3RpdmF0ZQpgYGAKCjQuIFN1bW1hcml6ZSB0aGUgb3V0cHV0IGZyb20gUGl4eSBmb3IgUFdTOTEgQ2hyMSAgCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9CnBpcGk8LXJlYWQudGFibGUoIi4uL0RhdGEvcGl4eS9QV1M5MS9QV1M5MV9jaDFfcGkudHh0IiwgaGVhZGVyPVQpCmdncGxvdChwaXBpLCBhZXMoeD13aW5kb3dfcG9zXzEsIHk9YXZnX3BpKSkrCiAgICBnZW9tX2xpbmUoY29sb3I9Ymx1KSt4bGFiKCcnKSt5bGFiKGV4cHJlc3Npb24oIm1lYW4gIipwaSkpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9waXh5X3BpX3B3czkxX2NoMV9saW5lLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gMy41LCBkcGk9MzAwKQpgYGAKIVtdKC4uL091dHB1dC9TRlMvcGl4eV9waV9wd3M5MV9jaDFfbGluZS5wbmcpe3dpZHRoPTc1JX0KYGBge3Igd2FybmluZz1GQUxTRSwgZWNobz1UUlVFfQpnZ3Bsb3QocGlwaSwgYWVzKHg9d2luZG93X3Bvc18xLCB5PWF2Z19waSkpKwogICAgZ2VvbV9wb2ludChzaXplPTAuMywgY29sb3I9ImdyYXkyMCIpCgptZWFuKHBpcGkkYXZnX3BpKQojIDAuMDAyNzg0NzEKCiN3ZWlnaHRlZCBtZWFuCnBpcGkkcGlfc3VtPC1waXBpJGF2Z19waSpwaXBpJG5vX3NpdGVzCnN1bShwaXBpJHBpX3N1bSkvc3VtKHBpcGkkbm9fc2l0ZXMpCiMgMC4wMDI3NzU0NjQKYGBgCgojIyBDb21wYXJlIM+AIGVzdGltYXRlZCBmcm9tIEFOR1NEIHZzLiBQaXh5CgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9CiNDb21wYXJlIHdpdGggdGhlIHBpIGVzdGltYXRlZCBmcm9tIEFOR1NEIFNGUyAKdGhldGE8LXJlYWQuZGVsaW0ocGFzdGUwKCcuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS91bmZvbGRlZC9QV1M5MV81MGt3aW5fMTBrc3RlcC5wZXN0UEcnKSkKdGhldGEkcGk8LXRoZXRhJHRQL3RoZXRhJG5TaXRlcwptZWFuKHRoZXRhJHBpW3RoZXRhJENocj09ImNocjEiXSkKIzAuMDAzODI2Mjk3CgojY2hyMSBjb21wYXJpc29uCmNoMTwtcGlwaVssYygiY2hyb21vc29tZSIsICJhdmdfcGkiKV0KY2gxJG1ldGhvZDwtIlBpeHkiCnRoZXRhMjwtdGhldGFbLGMoIkNociIsInBpIildCnRoZXRhMiRtZXRob2Q8LSJBTkdTRCIKY29sbmFtZXMoY2gxKVsxOjJdPC1jKCJDaHIiLCJwaSIpCmNoMTwtcmJpbmQoY2gxLHRoZXRhMikKCgpnZ3Bsb3QoY2gxLCBhZXMoeD1tZXRob2QsIHk9cGkpKSsKICAgIGdlb21fYm94cGxvdChhZXMobWlkZGxlPW1lYW4ocGkpLCBjb2xvcj1tZXRob2QpLG91dGxpZXIuYWxwaGEgPSAwLjIpKwogICAgdGhlbWVfY2xhc3NpYygpK3hsYWIoJycpK3lsYWIoZXhwcmVzc2lvbihwaSkpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMWY3OGI0IiwiI2ZiOWE5OSIpLCBndWlkZT0nbm9uZScpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2QucHdzOTEuY2gxLnBuZyIsIHdpZHRoPTQsIGhlaWdodD00LGRwaT0yMDAgKQpgYGAKIVtdKC4uL091dHB1dC9TRlMvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkLnB3czkxLmNoMS5wbmcpe3dpZHRoPTUwJX0KCiMjIyBSdW4gUGl4eSBmb3IgYWxsIGNocm9tb3NvbWVzIGZvciBQV1MgCgpgYGB7YmFzaCBlY2hvPVRSVUV9CiNpbmRleCB2Y2YgZmlsZXMgZm9yIGFsbCBjaHJvbW9zb21lcwpmb3IgZiBpbiAqLnZjZi5nejsgZG8KZmlsZW5hbWU9JChiYXNlbmFtZSAkZikKdGFiaXggJGYgCmRvbmUKYGBgCgoKYGBge3IgZWNobytUUlVFfQojY3JlYXRlIGEgc2NyaXB0IHRvIHJ1biBwaXh5CmZvciAoaiBpbiAxOiBsZW5ndGgocG9wcykpewogICAgc2luayhwYXN0ZTAoIi4uL0RhdGEvcGl4eS9ydW5waXh5XyIsIHBvcHNbal0sIi5zaCIpKQogICAgY2F0KCIjIS9iaW4vYmFzaFxuXG4iKQogICAgZm9yIChpIGluIDE6MjYpewogICAgICAgIGNhdChwYXN0ZTAoInBpeHkgLS1zdGF0cyBwaSAtLXZjZiAiLHBvcHNbal0sIl9jaCIsaSwiLnZjZi5neiAtLXBvcHVsYXRpb25zICIscG9wc1tqXSwicG9wLnR4dCAtLXdpbmRvd19zaXplIDEwMDAwIC0tbl9jb3JlIDggLS1vdXRwdXRfcHJlZml4ICIscG9wc1tqXSwgIl9jaCIsaSwgIlxuIikpCiAgICB9CiAgICBzaW5rKE5VTEwpCn0KYGBgCgpgYGB7YmFzaCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQojUnVuIHBpeHkgCmJhc2ggcnVucGl4eV9QV1MxNy5zaAojcGl4eSBzY3JpcHQgZXhhbXBsZToKcGl4eSAtLXN0YXRzIHBpIC0tdmNmIFBXUzE3X2NoMjYudmNmLmd6IC0tcG9wdWxhdGlvbnMgUFdTMTdwb3AudHh0IC0td2luZG93X3NpemUgMTAwMDAgLS1uX2NvcmUgOCAtLW91dHB1dF9wcmVmaXggUFdTMTdfY2gyNgpgYGAKCgojIyMgUGxvdCB0aGUgb3V0cHV0cyBmcm9tIFBpeHkgZm9yIGFsbCBQV1MgZ3JvdXBzCmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNyZWFkIHRoZSBvdXRwdXQgZmlsZSBmb3IgUFdTOgpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpCgpmb3IgKHAgaW4gMSA6IGxlbmd0aChwb3BzKSl7CiAgICBwaXh5PC1kYXRhLmZyYW1lKCkKICAgIGZvciAoaSBpbiAxOjI2KXsKICAgICAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvcGl4eS8iLHBvcHNbcF0sIi8iLHBvcHNbcF0sIl9jaCIsaSwiX3BpLnR4dCIpLCBoZWFkZXI9VCkKICAgICAgICBkZiRtZXRob2Q8LSJQaXh5IgogICAgICAgIGRmJFdpbkNlbnRlcjwtZGYkd2luZG93X3Bvc18yLTUwMDAKICAgICAgICBkZjwtZGZbLGMoImNocm9tb3NvbWUiLCJXaW5DZW50ZXIiLCJhdmdfcGkiLCJtZXRob2QiKV0KICAgICAgICBjb2xuYW1lcyhkZilbYygxLDMpXTwtYygiQ2hyIiwicGkiKQogICAgICAgIHBpeHk8LXJiaW5kKHBpeHksIGRmKQogICAgfQogICAgd3JpdGUuY3N2KHBpeHksIHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1twXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSkKICAgIAogICAgI0NvbXBhcmUgd2l0aCB0aGUgcGkgZXN0aW1hdGVkIGZyb20gQU5HU0QgU0ZTIAogICAgdGhldGE8LXJlYWQuZGVsaW0ocGFzdGUwKCcuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS91bmZvbGRlZC8nLHBvcHNbcF0sJ181MGt3aW5fMTBrc3RlcC5wZXN0UEcnKSkKICAgIHRoZXRhJHBpPC10aGV0YSR0UC90aGV0YSRuU2l0ZXMKICAgIHRoZXRhJG1ldGhvZDwtIkFOR1NEIgogICAgcGk8LXJiaW5kKHBpeHksIHRoZXRhWyxjKCJDaHIiLCJXaW5DZW50ZXIiLCJwaSIsIm1ldGhvZCIpXSkKCiAgICBwaSRDaHI8LWZhY3RvcihwaSRDaHIsIGxldmVscz1wYXN0ZTAoImNociIsMToyNikpCiAgICBnZ3Bsb3QocGksIGFlcyh4PUNociwgeT1waSwgY29sb3I9bWV0aG9kKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhtaWRkbGU9bWVhbihwaSkpLG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNikrCiAgICAgICAgdGhlbWVfY2xhc3NpYygpK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdCA9MSkpKwogICAgICAgIHhsYWIoIiIpK3lsYWIoZXhwcmVzc2lvbihwaSkpK2dndGl0bGUocG9wc1twXSkrCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMWY3OGI0IiwiI2ZiOWE5OSIpKQogICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1BpL1BpX2NvbXBhcmlzb25fcGl4eS52cy5hbmdzZC4iLHBvcHNbcF0sICIucG5nIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDUsIGRwaT0xMDApCiAgICAKICAgICMgZ2Vub21lLXdpZGUgbWVhbiBwaSBjb21wYXJpc29uCiAgICBtZWFucyA8LSBhZ2dyZWdhdGUocGkgfiAgbWV0aG9kLCBwaSwgbWVhbikKICAgIAogICAgZ2dwbG90KHBpLCBhZXMoeD1tZXRob2QsIHk9cGkpKSsKICAgICAgICBnZW9tX2JveHBsb3QoYWVzKGNvbG9yPW1ldGhvZCksIG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNikrCiAgICAgICAgdGhlbWVfY2xhc3NpYygpKyBnZ3RpdGxlKHBvcHNbcF0pKwogICAgICAgIGdlb21fcG9pbnQoc3RhdCA9ICJzdW1tYXJ5IiwgZnVuID0gIm1lYW4iLCBjb2xvcj0iZ3JheTQwIikrCiAgICAgICAgIHhsYWIoIiIpK3lsYWIoZXhwcmVzc2lvbihwaSkpKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzFmNzhiNCIsIiNmYjlhOTkiKSwgZ3VpZGU9J25vbmUnKSsKICAgICAgICBnZW9tX3RleHQoZGF0YSA9IG1lYW5zLCBhZXMobGFiZWwgPSByb3VuZChwaSwgZGlnaXRzPTUpLCB5ID0gcGkgKyAwLjAyKSwgY29sb3I9ImdyYXk0MCIpCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkX21lYW5fIixwb3BzW3BdLCIucG5nIiksIHdpZHRoID0gMywgaGVpZ2h0ID0gMywgZHBpPTIwMCkKfQoKYGBgCgohW10oLi4vT3V0cHV0L1BpL1BpX2NvbXBhcmlzb25fcGl4eS52cy5hbmdzZF9tZWFuX1BXUzkxLnBuZyl7d2lkdGg9MzAlfSAhW1BXUzkxXSguLi9PdXRwdXQvUGkvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkX1BXUzkxLnBuZyl7d2lkdGg9NjAlfSAKCiFbUFdTMDddKC4uL091dHB1dC9QaS9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2RfbWVhbl9QV1MwNy5wbmcpe3dpZHRoPTMwJX0hW10oLi4vT3V0cHV0L1BpL1BpX2NvbXBhcmlzb25fcGl4eS52cy5hbmdzZC5QV1MwNy5wbmcpe3dpZHRoPTYwJX0gIAoKIVtQV1MxN10oLi4vT3V0cHV0L1BpL1BpX2NvbXBhcmlzb25fcGl4eS52cy5hbmdzZF9tZWFuX1BXUzE3LnBuZyl7d2lkdGg9MzAlfSFbXSguLi9PdXRwdXQvUGkvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkLlBXUzE3LnBuZyl7d2lkdGg9NjAlfSAgCgotICoqUGl4eSBlc3RpbWF0ZXMgaGF2ZSBtb3JlIHZhcmlhYmlsaXR5KioKLSAqKlBpeHkgZXNpdG1hdGVzIGFyZSBzbGlnaHRseSBsb3dlciB0aGFuIEFOU0dEIGVzdGlhbXRlcyoqCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgQXNzZXNzIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIEFOR1NEIGFuZCBQaXh5CnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKZGlmZjwtZGF0YS5mcmFtZShwb3A9cG9wcykKZm9yIChwIGluIDEgOiBsZW5ndGgocG9wcykpewogICAgcGl4eTwtZGF0YS5mcmFtZSgpCiAgICBmb3IgKGkgaW4gMToyNil7CiAgICAgICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW3BdLCIvIixwb3BzW3BdLCJfY2giLGksIl9waS50eHQiKSwgaGVhZGVyPVQpCiAgICAgICAgZGYkbWV0aG9kPC0iUGl4eSIKICAgICAgICBkZiRXaW5DZW50ZXI8LWRmJHdpbmRvd19wb3NfMi01MDAwCiAgICAgICAgZGY8LWRmWyxjKCJjaHJvbW9zb21lIiwiV2luQ2VudGVyIiwiYXZnX3BpIiwibWV0aG9kIildCiAgICAgICAgY29sbmFtZXMoZGYpW2MoMSwzKV08LWMoIkNociIsInBpIikKICAgICAgICBwaXh5PC1yYmluZChwaXh5LCBkZikKICAgIH0KICAgICNtZWFuLnBpeHk8LWFnZ3JlZ2F0ZShwaXh5JHBpLCBieT1saXN0KHBpeHkkQ2hyKSwgbWVhbiwgbmEucm09VCkKICAgIAogICAgI1BpIGVzdGltYXRlZCBmcm9tIEFOR1NEIFNGUyAKICAgIHRoZXRhPC1yZWFkLmRlbGltKHBhc3RlMCgnLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vdW5mb2xkZWQvJyxwb3BzW3BdLCdfNTBrd2luXzEwa3N0ZXAucGVzdFBHJykpCiAgICB0aGV0YSRwaTwtdGhldGEkdFAvdGhldGEkblNpdGVzCiAgICB0aGV0YSRtZXRob2Q8LSJBTkdTRCIKICAgIHBpPC1yYmluZChwaXh5LCB0aGV0YVssYygiQ2hyIiwiV2luQ2VudGVyIiwicGkiLCJtZXRob2QiKV0pCgogICAgbWVhbnM8LWFnZ3JlZ2F0ZShwaSRwaSwgYnk9bGlzdChwaSRtZXRob2QpLCBtZWFuLCBuYS5ybT1UKQogICAgCiAgICAjZGlmZmVyZW5jZXMgaW4gcGkgZXN0aW1hdGVzCiAgICAKICAgIGRpZmYkcHJvcC5kaWZmZXJlbmNlW3BdPC1tZWFucyR4W21lYW5zJEdyb3VwLjE9PSJBTkdTRCJdL21lYW5zJHhbbWVhbnMkR3JvdXAuMT09IlBpeHkiXQp9CgoKa25pdHI6OmthYmxlKGRpZmYpCgpgYGAKCgoKCiMjIyBDb21wYXJlIGFjcm9zcyB5ZWFycyAtUFdTCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cgpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpClBpPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIHBpPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9QaS8iLHBvcHNbaV0sICJfUGlfcGl4eV9wZXI1MGtXaW5kb3cuY3N2IiksIHJvdy5uYW1lcyA9MSApCiAgICBwaSRDaHI8LWZhY3RvcihwaSRDaHIsIGxldmVscz1wYXN0ZTAoImNociIsMToyNikpCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKCm1lYW5zIDwtIGFnZ3JlZ2F0ZShwaSB+IHBvcCxQaSwgbWVhbikKZ2dwbG90KFBpLCBhZXMoeD1wb3AsIHk9cGksIGNvbG9yPXBvcCkpKwogICAgICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9cG9wKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkrIGdndGl0bGUoIlBXUyIpKwogICAgICAgIGdlb21fcG9pbnQoc3RhdCA9ICJzdW1tYXJ5IiwgZnVuID0gIm1lYW4iLCBjb2xvcj0iZ3JheTQwIikrCiAgICAgICAgIHhsYWIoIiIpK3lsYWIoZXhwcmVzc2lvbihwaSkpKwogICAgICAgIGdlb21fdGV4dChkYXRhID0gbWVhbnMsIGFlcyhsYWJlbCA9IHJvdW5kKHBpLCBkaWdpdHM9NSksIHkgPSBwaSArIDAuMDIpLCBjb2xvcj0iZ3JheTQwIikKZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1BpL1BpX3BpeHlfbWVhbi4iLHBvcHNbaV0sIi5wbmciKSwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDMsIGRwaT0yMDApCmBgYAoKIVtdKC4uL091dHB1dC9QaS9QaV9waXh5X21lYW4uUFdTLnBuZyl7d2lkdGg9NjAlfQoKCmBgYHtyICBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNyZWFkIHRoZSBvdXRwdXQgZmlsZSBmb3IgZWFjaCBwb3BzOgpwb3BzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IikKCmZvciAocCBpbiAxIDogbGVuZ3RoKHBvcHMpKXsKICAgIHBpeHk8LWRhdGEuZnJhbWUoKQogICAgZm9yIChpIGluIDE6MjYpewogICAgICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9waXh5LyIscG9wc1twXSwiLyIscG9wc1twXSwiX2NoIixpLCJfcGkudHh0IiksIGhlYWRlcj1UKQogICAgICAgIGRmJG1ldGhvZDwtIlBpeHkiCiAgICAgICAgZGYkV2luQ2VudGVyPC1kZiR3aW5kb3dfcG9zXzItNTAwMAogICAgICAgIGRmPC1kZlssYygiY2hyb21vc29tZSIsIldpbkNlbnRlciIsImF2Z19waSIsIm1ldGhvZCIpXQogICAgICAgIGNvbG5hbWVzKGRmKVtjKDEsMyldPC1jKCJDaHIiLCJwaSIpCiAgICAgICAgcGl4eTwtcmJpbmQocGl4eSwgZGYpCiAgICB9CiAgICB3cml0ZS5jc3YocGl4eSwgcGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW3BdLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpKQp9CgpQaTwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOmxlbmd0aChwb3BzKSl7CiAgICBwaTwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW2ldLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpLCByb3cubmFtZXMgPTEgKQoKICAgIHBpJENocjwtZmFjdG9yKHBpJENociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgIGdncGxvdChwaSwgYWVzKHg9Q2hyLCB5PXBpKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhtaWRkbGU9bWVhbihwaSkpLG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNixjb2xvcj0iIzFmNzhiNCIpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPTEpKSsKICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKStnZ3RpdGxlKHBvcHNbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfcGl4eS5wZXJDaHJvbS4iLHBvcHNbaV0sICIucG5nIiksIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQogICAgCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKbWVhbnMgPC0gYWdncmVnYXRlKHBpIH4gcG9wLFBpLCBtZWFuKQpnZ3Bsb3QoUGksIGFlcyh4PXBvcCwgeT1waSwgY29sb3I9cG9wKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvcj1wb3ApLCBvdXRsaWVyLmFscGhhID0gMC4yLCBvdXRsaWVyLnNpemUgPSAwLjYpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSsgZ2d0aXRsZSgiVEIiKSsKICAgICAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgY29sb3I9ImdyYXk0MCIpKwogICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKSsKICAgICAgICBnZW9tX3RleHQoZGF0YSA9IG1lYW5zLCBhZXMobGFiZWwgPSByb3VuZChwaSwgZGlnaXRzPTUpLCB5ID0gcGkgKyAwLjAyKSwgY29sb3I9ImdyYXk0MCIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X21lYW4uVEIucG5nIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLCBkcGk9MjAwKQpgYGAKCiFbXSguLi9PdXRwdXQvUGkvUGlfcGl4eV9tZWFuLlRCLnBuZyl7d2lkdGg9NzAlfQoKCmBgYHtyICBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQojcmVhZCB0aGUgb3V0cHV0IGZpbGUgZm9yIGVhY2ggU1MgcG9wOgpwb3BzPC1jKCJTUzk2IiwiU1MwNiIsIlNTMTciKQpmb3IgKHAgaW4gMSA6IGxlbmd0aChwb3BzKSl7CiAgICBwaXh5PC1kYXRhLmZyYW1lKCkKICAgIGZvciAoaSBpbiAxOjI2KXsKICAgICAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvcGl4eS8iLHBvcHNbcF0sIi8iLHBvcHNbcF0sIl9jaCIsaSwiX3BpLnR4dCIpLCBoZWFkZXI9VCkKICAgICAgICBkZiRtZXRob2Q8LSJQaXh5IgogICAgICAgIGRmJFdpbkNlbnRlcjwtZGYkd2luZG93X3Bvc18yLTUwMDAKICAgICAgICBkZjwtZGZbLGMoImNocm9tb3NvbWUiLCJXaW5DZW50ZXIiLCJhdmdfcGkiLCJtZXRob2QiKV0KICAgICAgICBjb2xuYW1lcyhkZilbYygxLDMpXTwtYygiQ2hyIiwicGkiKQogICAgICAgIHBpeHk8LXJiaW5kKHBpeHksIGRmKQogICAgfQogICAgd3JpdGUuY3N2KHBpeHksIHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1twXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSkKfQoKUGk8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgcGk8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIHBpJENocjwtZmFjdG9yKHBpJENociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgIGdncGxvdChwaSwgYWVzKHg9Q2hyLCB5PXBpKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhtaWRkbGU9bWVhbihwaSkpLG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNixjb2xvcj0iIzFmNzhiNCIpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPTEpKSsKICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKStnZ3RpdGxlKHBvcHNbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfcGl4eS5wZXJDaHJvbS4iLHBvcHNbaV0sICIucG5nIiksIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQogICAgCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKbWVhbnMgPC0gYWdncmVnYXRlKHBpIH4gcG9wLFBpLCBtZWFuKQoKZ2dwbG90KFBpLCBhZXMoeD1wb3AsIHk9cGksIGNvbG9yPXBvcCkpKwogICAgICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9cG9wKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgZ2VvbV9wb2ludChzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGNvbG9yPSJncmF5NDAiKSsKICAgICAgICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrZ2d0aXRsZSgiU1MiKSsKICAgICAgICBnZW9tX3RleHQoZGF0YSA9IG1lYW5zLCBhZXMobGFiZWwgPSByb3VuZChwaSwgZGlnaXRzPTUpLCB5ID0gcGkgKyAwLjAyKSwgY29sb3I9ImdyYXk0MCIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X21lYW4uU1MucG5nIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLCBkcGk9MjAwKQpgYGAKCiFbXSguLi9PdXRwdXQvUGkvUGlfcGl4eV9tZWFuLlNTLnBuZyl7d2lkdGg9NjAlfQoKCmBgYHtyICBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQogCiNyZWFkIHRoZSBvdXRwdXQgZmlsZSBmb3IgZWFjaCBwb3BzOgpwb3BzPC1jKCJCQzE3IiwiQ0ExNyIsIldBMTciKQpmb3IgKHAgaW4gMSA6IGxlbmd0aChwb3BzKSl7CiAgICBwaXh5PC1kYXRhLmZyYW1lKCkKICAgIGZvciAoaSBpbiAxOjI2KXsKICAgICAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvcGl4eS8iLHBvcHNbcF0sIi8iLHBvcHNbcF0sIl9jaCIsaSwiX3BpLnR4dCIpLCBoZWFkZXI9VCkKICAgICAgICBkZiRtZXRob2Q8LSJQaXh5IgogICAgICAgIGRmJFdpbkNlbnRlcjwtZGYkd2luZG93X3Bvc18yLTUwMDAKICAgICAgICBkZjwtZGZbLGMoImNocm9tb3NvbWUiLCJXaW5DZW50ZXIiLCJhdmdfcGkiLCJtZXRob2QiKV0KICAgICAgICBjb2xuYW1lcyhkZilbYygxLDMpXTwtYygiQ2hyIiwicGkiKQogICAgICAgIHBpeHk8LXJiaW5kKHBpeHksIGRmKQogICAgfQogICAgd3JpdGUuY3N2KHBpeHksIHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1twXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSkKfQoKUGk8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgcGk8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIHBpJENocjwtZmFjdG9yKHBpJENociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgIGdncGxvdChwaSwgYWVzKHg9Q2hyLCB5PXBpKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhtaWRkbGU9bWVhbihwaSkpLG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNixjb2xvcj0iIzFmNzhiNCIpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPTEpKSsKICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKStnZ3RpdGxlKHBvcHNbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfcGl4eS5wZXJDaHJvbS4iLHBvcHNbaV0sICIucG5nIiksIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQogICAgCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKbWVhbnMgPC0gYWdncmVnYXRlKHBpIH4gcG9wLFBpLCBtZWFuKQoKZ2dwbG90KFBpLCBhZXMoeD1wb3AsIHk9cGksIGNvbG9yPXBvcCkpKwogICAgICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9cG9wKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgZ2VvbV9wb2ludChzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGNvbG9yPSJncmF5NDAiKSsKICAgICAgICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrCiAgICAgICAgZ2VvbV90ZXh0KGRhdGEgPSBtZWFucywgYWVzKGxhYmVsID0gcm91bmQocGksIGRpZ2l0cz01KSwgeSA9IHBpICsgMC4wMiksIGNvbG9yPSJncmF5NDAiKQojZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1BpL1BpX3BpeHlfbWVhbi5DQS5CQy5XQS5wbmciKSwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDMsIGRwaT0yMDApCmBgYAoKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IikKeWVhcjwtYygxOTkxLDE5OTYsMjAwNywyMDE3LDE5OTEsMTk5NiwyMDA2LDIwMTcsMTk5NiwyMDA2LDIwMTcpCm1lYW5QaTwtZGF0YS5mcmFtZShwb3AueXI9cG9wcywgeWVhcj15ZWFyKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIG1lYW5QaSRtZWFuW2ldPC1tZWFuKGRmJHBpLCBuYS5ybT1UKQogICAgbWVhblBpJHBvcFtpXTwtZ3N1YigiXFxkLisiLCIiLHBvcHNbaV0pCn0KCgpnZ3Bsb3QobWVhblBpLCBhZXMoeD15ZWFyLCB5PW1lYW4sIGNvbG9yPXBvcCkpKwogICAgZ2VvbV9wb2ludChzaXplPTMpKwogICAgZ2VvbV9saW5lKCkrCiAgICB4bGFiKCIiKSt5bGFiKHBhc3RlMCgiTWVhbiAiLGV4cHJlc3Npb24ocGkpKSkrCiAgICB0aGVtZV9saW5lZHJhdygpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzW2MoMiwxLDUpXSkKZ2dzYXZlKCIuLi9PdXRwdXQvUGkvUGlfb3ZlclllYXJzLlBXUy5UQi5TUy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaT0zMDApCgpgYGAKIVtdKC4uL091dHB1dC9QaS9QaV9vdmVyWWVhcnMuUFdTLlRCLlNTLnBuZyl7d2lkdGg9NjUlfQoKCmBgYHtyICBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQoKcG9wczwtYygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIsIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikKeWVhcjwtYygxOTkxLDE5OTYsMjAwNiwyMDE3LDE5OTEsMTk5NiwyMDA3LDIwMTcsMTk5NiwyMDA2LDIwMTcsMjAxNywyMDE3LDIwMTcpCm1lYW5QaTwtZGF0YS5mcmFtZShwb3AueXI9cG9wcywgeWVhcj15ZWFyKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIG1lYW5QaSRtZWFuW2ldPC1tZWFuKGRmJHBpLCBuYS5ybT1UKQogICAgbWVhblBpJHBvcFtpXTwtZ3N1YigiXFxkLisiLCIiLHBvcHNbaV0pCn0KCiNNZWFuIHBpIGNvbXBhcmlzb24KbWVhblBpJHBvcC55cjwtZmFjdG9yKG1lYW5QaSRwb3AueXIsIGxldmVscz1wb3BzKQptZWFuUGkkcG9wPC1mYWN0b3IobWVhblBpJHBvcCwgbGV2ZWxzPWMoIlRCIiwiUFdTIiwiU1MiLCJCQyIsIldBIiwiQ0EiKSkKCmdncGxvdChtZWFuUGksIGFlcyh4PXBvcC55ciwgeT1tZWFuLCBjb2xvcj1wb3ApKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zKSsKICAgIHhsYWIoIiIpK3lsYWIocGFzdGUwKCJNZWFuICIsZXhwcmVzc2lvbihwaSkpKSsKICAgIHRoZW1lX2xpbmVkcmF3KCkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHNbYyg1LDIsMSwgNCw2LDcpXSkrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpCmdnc2F2ZSgiLi4vT3V0cHV0L1BpL21lYW5QaV9lc3RpbWF0ZWQuZnJvbS5QaXh5LnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpPTMwMCkKCmBgYAohW10oLi4vT3V0cHV0L1BpL21lYW5QaV9lc3RpbWF0ZWQuZnJvbS5QaXh5LnBuZyl7d2lkdGg9NzAlfQoKYGBge3IgIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9Cgpwb3BzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IiwiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJTUzk2IiwiU1MwNiIsIlNTMTciLCJCQzE3IiwiV0ExNyIsIkNBMTciKQojeWVhcjwtYygxOTkxLDE5OTYsMjAwNiwyMDE3LDE5OTEsMTk5NiwyMDA3LDIwMTcsMTk5NiwyMDA2LDIwMTcsMjAxNywyMDE3LDIwMTcpCgpQaTwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOmxlbmd0aChwb3BzKSl7CiAgICBwaTwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW2ldLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpLCByb3cubmFtZXMgPTEgKQogICAgcGkkcG9wLnlyPC1wb3BzW2ldCiAgICBwaSRwb3A8LWdzdWIoIlxcZC4rIiwiIixwb3BzW2ldKQogICAgUGk8LXJiaW5kKFBpLHBpKQp9CgpQaSRwb3AueXI8LWZhY3RvcihQaSRwb3AueXIsIGxldmVscz1wb3BzKQpQaSRwb3A8LWZhY3RvcihQaSRwb3AsIGxldmVscz1jKCJUQiIsIlBXUyIsIlNTIiwiQkMiLCJXQSIsIkNBIikpCiNtZWFucyA8LSBhZ2dyZWdhdGUocGkgfiBwb3AueXIsUGksIG1lYW4pCmdncGxvdChQaSwgYWVzKHg9cG9wLnlyLCB5PXBpLCBjb2xvcj1wb3ApKSsKICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9cG9wKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgIHRoZW1lX2NsYXNzaWMoKSsgCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgY29sb3I9ImdyYXk0MCIpKwogICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrCiAgICBnZW9tX3BvaW50KHN0YXQ9InN1bW1hcnkiLCBmdW49bWVhbikrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHNbYyg1LDIsMSwgNCw2LDcpXSkKICAgICNnZW9tX3RleHQoZGF0YSA9IG1lYW5zLCBhZXMobGFiZWwgPSByb3VuZChwaSwgZGlnaXRzPTUpLCB5ID0gcGkgKyAwLjAyKSwgY29sb3I9ImdyYXk0MCIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X2FsbF9ib3hwbG90LnBuZyIpLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMywgZHBpPTIwMCkKCmdncGxvdChQaSwgYWVzKHg9cG9wLnlyLCB5PXBpLCBjb2xvcj1wb3AsIGZpbGw9cG9wKSkrCiAgICBnZW9tX2JveHBsb3QoYWVzKGNvbG9yPXBvcCksIG91dGxpZXIuYWxwaGEgPSAwLjEsIG91dGxpZXIuc2l6ZSA9IDAuMykrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgY29sb3I9ImdyYXk0MCIpKwogICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkreWxpbSgwLDAuMDA0NykrCiAgICBnZW9tX3BvaW50KHN0YXQ9InN1bW1hcnkiLCBmdW49bWVhbiwgc2l6ZT0yLjUpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXN0ZTAoY29scywgIjk5IikpKwogICAgdGhlbWUoYXhpcy50aXRsZS55ID0gIGVsZW1lbnRfdGV4dChzaXplPTE1KSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQogICAgCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X2FsbF9ib3hwbG90X3pvb21lZDIucG5nIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gMy40LCBkcGk9MzAwKQpgYGAKIVtdKC4uL091dHB1dC9QaS9QaV9waXh5X2FsbF9ib3hwbG90X3pvb21lZC5wbmcpe3dpZHRoPTc1JX0KCgoKIyMjIEJvb3RzdHJhcCBwaSB2YWx1ZXMgdG8gZ2V0IDk1JSBDSQoKYGBge3J9CgojIGF2ZXJhZ2UgdGhldGEgdmFsdWVzIGFjcm9zcyBzaXRlcwoKIyMjIyMjIyMjIyMjIwojIFBhcmFtZXRlcnMKIyMjIyMjIyMjIyMjIwojIG51bWJlciBvZiBjaHJvbW9zb21lcyBpbiBlYWNoIHNhbXBsZQojbmNockNhbjQwIDwtIDQyICMgc2FtcGxlIHNpemUgaW4gIyBjaHJvbW9zb21lcwojbmNockNhbjE0IDwtIDQ4CiNuY2hyTG9mMDcgPC0gNDQKI25jaHJMb2YxMSA8LSA0OAojbmNockxvZjE0IDwtIDQ0CgpuYm9vdCA8LSAxMDAwCgpuY2hyPTI2CgojIyMjIyMjIyMjIyMjIyMjIyMjIwojIGxvYWQgZnVuY3Rpb25zCnJlcXVpcmUoZGF0YS50YWJsZSkKcmVxdWlyZShib290KSAjIGZvciBib290c3RyYXAgQ0lzCgoKIyBGb3IgVGFqaW1hJ3MgRCBjYWxjcy4gQWZ0ZXIgaHR0cHM6Ly9naXRodWIuY29tL0FOR1NEL2FuZ3NkL2Jsb2IvbWFzdGVyL21pc2Mvc3RhdHMuY3BwCmExZiA8LSBmdW5jdGlvbihuc2FtKSByZXR1cm4oc3VtKDEvc2VxKDEsIG5zYW0tMSkpKQphMmYgPC0gZnVuY3Rpb24obnNhbSkgcmV0dXJuKHN1bSgxLyhzZXEoMSwgbnNhbS0xKSpzZXEoMSwgbnNhbS0xKSkpKQpiMWYgPC0gZnVuY3Rpb24obnNhbSkgcmV0dXJuKChuc2FtICsgMSkvKDMqKG5zYW0tMSkpKQpiMmYgPC0gZnVuY3Rpb24obnNhbSkgcmV0dXJuKCgyKihuc2FtKm5zYW0gKyBuc2FtICsgMykpLyg5Km5zYW0qKG5zYW0gLSAxKSkpCmMxZiA8LSBmdW5jdGlvbihhMSwgYjEpIHJldHVybihiMSAtICgxL2ExKSkKYzJmIDwtIGZ1bmN0aW9uKG5zYW0sIGExLCBhMiwgYjIpIHJldHVybihiMiAtICgobnNhbSArIDIpLyhhMSpuc2FtKSkgKyAoYTIvKGExICogYTEpKSkKZTFmIDwtIGZ1bmN0aW9uKGExLCBjMSkgcmV0dXJuKGMxL2ExKQplMmYgPC0gZnVuY3Rpb24oYTEsIGEyLCBjMikgcmV0dXJuKGMyLygoYTEqYTEpICsgYTIpKQoKIyBUYWppbWEncyBEIGNhbGN1bGF0aW9uCiMgbnNhbTogc2FtcGxlIHNpemUKIyB0aGV0YVc6IFdhdHRlcnNvbidzIHRoZXRhICgjIHNlZ3JlZ2F0aW5nIHNpdGVzIC8gYTEpCiMgc3VtazogdGhldGEgcGkgKGF2ZXJhZ2UgbnVtYmVyIG9mIFNOUHMgaW4gcGFpcndpc2UgY29tcGFyaXNvbnMpCiMgYWZ0ZXIgaHR0cHM6Ly9naXRodWIuY29tL0FOR1NEL2FuZ3NkL2Jsb2IvbWFzdGVyL21pc2Mvc3RhdHMuY3BwCnRhamQgPC0gZnVuY3Rpb24obnNhbSwgdGhldGFXLCBzdW1rKXsKCWExIDwtIGExZihuc2FtKQoJc2Vnc2l0ZXMgPC0gdGhldGFXICogYTEKCWlmKHNlZ3NpdGVzID09IDApIHJldHVybigwKQoJYTIgPC0gYTJmKG5zYW0pCgliMSA8LSBiMWYobnNhbSkKICAJYjIgPC0gYjJmKG5zYW0pCgljMSA8LSBjMWYoYTEsIGIxKQoJYzIgPC0gYzJmKG5zYW0sIGExLCBhMiwgYjIpCgllMSA8LSBlMWYoYTEsIGMxKQoJZTIgPC0gZTJmKGExLCBhMiwgYzIpCglyZXMgPC0gKHN1bWsgLSAodGhldGFXKSkvc3FydCgoZTEqc2Vnc2l0ZXMpICsgKChlMipzZWdzaXRlcykqKHNlZ3NpdGVzLTEpKSkKCXJldHVybihyZXMpCn0KCiMgY2FsYyB0aGV0YXMKY2FsY3RoZXRhcyA8LSBmdW5jdGlvbihkYXQsIG5jaHIsIG5sb2NpKXsKCSMgY2FsYyBhdmUgdGhldGEKCXRoZXRhcyA8LSBhcy5udW1lcmljKGRhdFssIC4odFcgPSBzdW0oZXhwKFdhdHRlcnNvbikvbmxvY2ksIG5hLnJtID0gVFJVRSksIHRQID0gc3VtKGV4cChQYWlyd2lzZSkvbmxvY2ksIG5hLnJtID0gVFJVRSkpXSkKCgkjIGNhbGN1bGF0ZSBUYWppbWEncyBECgl0aGV0YXNbM10gPC0gdGFqZChuY2hyLCB0aGV0YXNbMV0sIHRoZXRhc1syXSkKCQoJI3JldHVybgoJbmFtZXModGhldGFzKSA8LSBjKCd0VycsICd0UCcsICd0RCcpCglyZXR1cm4odGhldGFzKQp9CgojIGNhbGN1bGF0ZSBzdGF0cyBmcm9tIHNwZWNpZmllZCBMR3MgZm9yIGJsb2NrIGJvb3RzdHJhcHBpbmcgYWNyb3NzIExHcwp0aGV0YWJsb2NrIDwtIGZ1bmN0aW9uKGxncywgaW5kaWNlcywgYWxsZGF0YSwgbmNociwgcmVncyl7CgkjIG1ha2UgYm9vdHN0cmFwcGVkIGRhdGFzZXQKCW15ZGF0YSA8LSBkby5jYWxsKCJyYmluZCIsIGxhcHBseShpbmRpY2VzLCBmdW5jdGlvbihuKSBzdWJzZXQoYWxsZGF0YSwgQ2hyb21vPT1sZ3Nbbl0pKSkKCQoJIyBjYWxjdWxhdGUgbnVtYmVyIG9mIGNhbGxhYmxlIGxvY2ksIGdpdmVuIHRoZSBMR3MgaW4gdGhpcyBib290c3RyYXBwZWQgc2FtcGxlCglubG9jaSA8LSByZWdzW0Nocm9tbyAlaW4lIGxncywgLihsZW4gPSBQb3MyIC0gUG9zMSArIDEpLCBieSA9IC4oQ2hyb21vLCBQb3MxKV1bLCBzdW0obGVuKV0gIyBzdW0gb2YgYnAgaW4gdGhlIGNhbGxhYmxlIHJlZ2lvbgoJCgkjIGNhbGMgdGhldGFzCgl0aGV0YXMgPC0gY2FsY3RoZXRhcyhteWRhdGEsIG5jaHIsIG5sb2NpKQoJCgkjIHJldHVybgoJcmV0dXJuKHRoZXRhcykKfQoKI3VzaW5nIHdpbmRvdyBiYXNlZCBhbmdzZCBmaWxlICh1c2UgcHJla25vd24gbG9jaSBpbiA1MDAwMCB3aW5kb3dzKQp0aGV0YWJsb2NrMiA8LSBmdW5jdGlvbihsZ3MsIGluZGljZXMsIGFsbGRhdGEsIG5jaHIsIHJlZ3MpewoJIyBtYWtlIGJvb3RzdHJhcHBlZCBkYXRhc2V0CglteWRhdGEgPC0gZG8uY2FsbCgicmJpbmQiLCBsYXBwbHkoaW5kaWNlcywgZnVuY3Rpb24obikgc3Vic2V0KGFsbGRhdGEsIENocm9tbz09bGdzW25dKSkpCgkKCSMgY2FsY3VsYXRlIG51bWJlciBvZiBjYWxsYWJsZSBsb2NpLCBnaXZlbiB0aGUgTEdzIGluIHRoaXMgYm9vdHN0cmFwcGVkIHNhbXBsZQoJI25sb2NpIDwtIHJlZ3NbQ2hyb21vICVpbiUgbGdzLCAuKGxlbiA9IFBvczIgLSBQb3MxICsgMSksIGJ5ID0gLihDaHJvbW8sIFBvczEpXVssIHN1bShsZW4pXSAjIHN1bSBvZiBicCBpbiB0aGUgY2FsbGFibGUgcmVnaW9uCgoJbmxvY2kgPC0gYWxsZGF0YVtDaHJvbW8gJWluJSBsZ3Msc3VtKG5TaXRlcyldICMgc3VtIG9mIGJwIGluIHRoZSBjYWxsYWJsZSByZWdpb24KCQoJIyBjYWxjIHRoZXRhcwoJdGhldGFzIDwtIGNhbGN0aGV0YXMobXlkYXRhLCBuY2hyLCBubG9jaSkKCQoJIyByZXR1cm4KCXJldHVybih0aGV0YXMpCn0KCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgTG9hZCBkYXRhCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKYWxsZGF0YTwtZGF0CiMgbG9hZCBhbGwgbG9jaSB0aGV0YSBjYWxjcwpkYXQ8LWZyZWFkKCcuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi9CQzE3X21hZjAwLnRoZXRhczUwa1dpbmRvdy5nei5wZXN0UEcnKQpzZXRuYW1lcyhkYXQsICdDaHInLCAnQ2hyb21vJykKCmRhdENhbjQwIDwtIGZyZWFkKCdhbmFseXNpcy90aGV0YXMuQ2FuXzQwLnBlc3RQRy5neicpCmRhdENhbjE0IDwtIGZyZWFkKCdhbmFseXNpcy90aGV0YXMuQ2FuXzE0LnBlc3RQRy5neicpCmRhdExvZjA3IDwtIGZyZWFkKCdhbmFseXNpcy90aGV0YXMuTG9mXzA3LnBlc3RQRy5neicpCmRhdExvZjExIDwtIGZyZWFkKCdhbmFseXNpcy90aGV0YXMuTG9mXzExLnBlc3RQRy5neicpCmRhdExvZjE0IDwtIGZyZWFkKCdhbmFseXNpcy90aGV0YXMuTG9mXzE0LnBlc3RQRy5neicpCgojIGdhdGsgbG9jaQpkYXRDYW40MGdhdGsgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5DYW5fNDAuZ2F0ay5wZXN0UEcuZ3onKQpkYXRDYW4xNGdhdGsgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5DYW5fMTQuZ2F0ay5wZXN0UEcuZ3onKQpkYXRMb2YwN2dhdGsgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5Mb2ZfMDcuZ2F0ay5wZXN0UEcuZ3onKQpkYXRMb2YxMWdhdGsgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5Mb2ZfMTEuZ2F0ay5wZXN0UEcuZ3onKQpkYXRMb2YxNGdhdGsgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5Mb2ZfMTQuZ2F0ay5wZXN0UEcuZ3onKQoKIyBmaXggbmFtZQpzZXRuYW1lcyhkYXRDYW40MCwgJyNDaHJvbW8nLCAnQ2hyb21vJykKc2V0bmFtZXMoZGF0Q2FuMTQsICcjQ2hyb21vJywgJ0Nocm9tbycpCnNldG5hbWVzKGRhdExvZjA3LCAnI0Nocm9tbycsICdDaHJvbW8nKQpzZXRuYW1lcyhkYXRMb2YxMSwgJyNDaHJvbW8nLCAnQ2hyb21vJykKc2V0bmFtZXMoZGF0TG9mMTQsICcjQ2hyb21vJywgJ0Nocm9tbycpCgpzZXRuYW1lcyhkYXRDYW40MGdhdGssICcjQ2hyb21vJywgJ0Nocm9tbycpCnNldG5hbWVzKGRhdENhbjE0Z2F0aywgJyNDaHJvbW8nLCAnQ2hyb21vJykKc2V0bmFtZXMoZGF0TG9mMDdnYXRrLCAnI0Nocm9tbycsICdDaHJvbW8nKQpzZXRuYW1lcyhkYXRMb2YxMWdhdGssICcjQ2hyb21vJywgJ0Nocm9tbycpCnNldG5hbWVzKGRhdExvZjE0Z2F0aywgJyNDaHJvbW8nLCAnQ2hyb21vJykKCndpbmRvd25hbWVzPC1jb2xuYW1lcyhkYXQpWzFdCmNvbG5hbWVzKGRhdClbMV08LSJ3aW5kb3ciCiMjIGxpc3Qgb2YgY2FsbGFibGUgcmVnaW9ucwoKZGF0JHdpbmRvdzwtZ3N1YigiXFwoIiwnJywgZGF0JHdpbmRvdykKZGF0JHdpbmRvdzwtZ3N1YigiXFwpJCIsJycsIGRhdCR3aW5kb3cpCmRhdCR3aW5kb3c8LWdzdWIoIlxcKSIsJywnLCBkYXQkd2luZG93KQp3aW5kb3dzMTwtc3RyX3NwbGl0X2ZpeGVkKGRhdCR3aW5kb3csIiwiLDYpIApjb2xuYW1lcyh3aW5kb3dzMSk8LWMoJ0luZGV4U3RhcnQnLCAnSW5kZXhTdG9wJywnZmlyc3RQb3Nfd2l0aERhdGEnLCdsYXN0UG9zX3dpdGhEYXRhJywnV2luU3RhcnQnLCdXaW5TdG9wJykKCmRhdDwtY2JpbmQod2luZG93czEsIGRhdCkKCnJlZ3M8LWRhdFssYygiQ2hyb21vIiwiV2luU3RhcnQiLCJXaW5TdG9wIildCm5hbWVzKHJlZ3MpPC1jKCdDaHJvbW8nLCAnUG9zMScsICdQb3MyJykKI3JlZ3MgPC0gZnJlYWQoJ2RhdGFfMjAyMC4wNS4wNy9DYWxsYWJsZV9iYXNlc19nYWRtb3IyLmJlZCcpCiNzZXRuYW1lcyhyZWdzLCBjKCdDaHJvbW8nLCAnUG9zMScsICdQb3MyJykpCiMKIyMgbGlzdCBvZiBubyBkYW1hZ2Ugc2l0ZXMKI25vZGFtIDwtIGZyZWFkKCdkYXRhXzIwMjAuMDUuMDcvR0FUS19maWx0ZXJlZF9TTlBfbm9fZGFtMi50YWInKQojc2V0bmFtZXMobm9kYW0sIGMoJ0Nocm9tbycsICdQb3MnLCAnUkVGJywgJ0FMVCcpKQojCiMKIyMgcmVtb3ZlIHVucGxhY2VkCiNkYXRDYW40MCA8LSBkYXRDYW40MFtncmVwKCdVbnBsYWNlZCcsIENocm9tbywgaW52ZXJ0ID0gVFJVRSksIF0KI2RhdENhbjE0IDwtIGRhdENhbjE0W2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQojZGF0TG9mMDcgPC0gZGF0TG9mMDdbZ3JlcCgnVW5wbGFjZWQnLCBDaHJvbW8sIGludmVydCA9IFRSVUUpLCBdCiNkYXRMb2YxMSA8LSBkYXRMb2YxMVtncmVwKCdVbnBsYWNlZCcsIENocm9tbywgaW52ZXJ0ID0gVFJVRSksIF0KI2RhdExvZjE0IDwtIGRhdExvZjE0W2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQojCiNkYXRDYW40MGdhdGsgPC0gZGF0Q2FuNDBnYXRrW2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQojZGF0Q2FuMTRnYXRrIDwtIGRhdENhbjE0Z2F0a1tncmVwKCdVbnBsYWNlZCcsIENocm9tbywgaW52ZXJ0ID0gVFJVRSksIF0KI2RhdExvZjA3Z2F0ayA8LSBkYXRMb2YwN2dhdGtbZ3JlcCgnVW5wbGFjZWQnLCBDaHJvbW8sIGludmVydCA9IFRSVUUpLCBdCiNkYXRMb2YxMWdhdGsgPC0gZGF0TG9mMTFnYXRrW2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQojZGF0TG9mMTRnYXRrIDwtIGRhdExvZjE0Z2F0a1tncmVwKCdVbnBsYWNlZCcsIENocm9tbywgaW52ZXJ0ID0gVFJVRSksIF0KCnJlZ3MgPC0gcmVnc1tDaHJvbW8gIT0gJ1VucGxhY2VkJywgXQpub2RhbSA8LSBub2RhbVtDaHJvbW8gIT0gJ1VucGxhY2VkJywgXQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgY3JlYXRlIHRhYmxlIG9mIGxvY2kgdHJpbW1lZCB0byBubyBkYW1hZ2Ugc2l0ZXMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpkYXRDYW40MGdhdGtuZCA8LSBtZXJnZShkYXRDYW40MCwgbm9kYW1bLCAuKENocm9tbywgUG9zKV0sIGJ5ID0gYygnQ2hyb21vJywgJ1BvcycpKSAjIHRyaW0KZGF0Q2FuMTRnYXRrbmQgPC0gbWVyZ2UoZGF0Q2FuMTQsIG5vZGFtWywgLihDaHJvbW8sIFBvcyldLCBieSA9IGMoJ0Nocm9tbycsICdQb3MnKSkgIyB0cmltCmRhdExvZjA3Z2F0a25kIDwtIG1lcmdlKGRhdExvZjA3LCBub2RhbVssIC4oQ2hyb21vLCBQb3MpXSwgYnkgPSBjKCdDaHJvbW8nLCAnUG9zJykpICMgdHJpbQpkYXRMb2YxMWdhdGtuZCA8LSBtZXJnZShkYXRMb2YxMSwgbm9kYW1bLCAuKENocm9tbywgUG9zKV0sIGJ5ID0gYygnQ2hyb21vJywgJ1BvcycpKSAjIHRyaW0KZGF0TG9mMTRnYXRrbmQgPC0gbWVyZ2UoZGF0TG9mMTQsIG5vZGFtWywgLihDaHJvbW8sIFBvcyldLCBieSA9IGMoJ0Nocm9tbycsICdQb3MnKSkgIyB0cmltCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBSdW4gdGhldGEgY2FsY3VsYXRpb25zCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiNubG9jaSA8LSByZWdzWywgLihsZW4gPSBQb3MyIC0gUG9zMSArIDEpLCBieSA9IC4oQ2hyb21vLCBQb3MxKV1bLCBzdW0obGVuKV0gIyBzdW0gb2YgYnAgaW4gdGhlIGNhbGxhYmxlIHJlZ2lvbgoKbmxvY2k8LWRhdCRuU2l0ZXMKCiMgYWxsIGxvY2kKY2FsY3RoZXRhcyhkYXQsIG5jaHIsIG5sb2NpKQpjYWxjdGhldGFzKGRhdENhbjE0LCBuY2hyQ2FuMTQsIG5sb2NpKQpjYWxjdGhldGFzKGRhdExvZjA3LCBuY2hyTG9mMDcsIG5sb2NpKQpjYWxjdGhldGFzKGRhdExvZjExLCBuY2hyTG9mMTEsIG5sb2NpKQpjYWxjdGhldGFzKGRhdExvZjE0LCBuY2hyTG9mMTQsIG5sb2NpKQoKIyBnYXRrIGxvY2kKY2FsY3RoZXRhcyhkYXRDYW40MGdhdGssIG5jaHJDYW40MCwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0Q2FuMTRnYXRrLCBuY2hyQ2FuMTQsIG5sb2NpKQpjYWxjdGhldGFzKGRhdExvZjA3Z2F0aywgbmNockxvZjA3LCBubG9jaSkKY2FsY3RoZXRhcyhkYXRMb2YxMWdhdGssIG5jaHJMb2YxMSwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMTRnYXRrLCBuY2hyTG9mMTQsIG5sb2NpKQoKIyBnYXRrIG5vIGRhbWFnZSBsb2NpCmNhbGN0aGV0YXMoZGF0Q2FuNDBnYXRrbmQsIG5jaHJDYW40MCwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0Q2FuMTRnYXRrbmQsIG5jaHJDYW4xNCwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMDdnYXRrbmQsIG5jaHJMb2YwNywgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMTFnYXRrbmQsIG5jaHJMb2YxMSwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMTRnYXRrbmQsIG5jaHJMb2YxNCwgbmxvY2kpCgoKCgojIGJsb2NrIGJvb3RzdHJhcHBpbmcgYWNyb3NzIExHcwoKI2xncyA8LSBkYXRDYW40MFssIHNvcnQodW5pcXVlKENocm9tbykpXQpkYXRsaXN0IDwtIGxpc3QoZGF0Q2FuNDAsIGRhdENhbjE0LCBkYXRMb2YwNywgZGF0TG9mMTEsIGRhdExvZjE0LCAKCQkJCWRhdENhbjQwZ2F0aywgZGF0Q2FuMTRnYXRrLCBkYXRMb2YwN2dhdGssIGRhdExvZjExZ2F0aywgZGF0TG9mMTRnYXRrLAoJCQkJZGF0Q2FuNDBnYXRrbmQsIGRhdENhbjE0Z2F0a25kLCBkYXRMb2YwN2dhdGtuZCwgZGF0TG9mMTFnYXRrbmQsIGRhdExvZjE0Z2F0a25kKQpuYW1lcyhkYXRsaXN0KSA8LSBjKCdDYW40MCBhbGwgbG9jaScsICdDYW4xNCBhbGwgbG9jaScsICdMb2YwNyBhbGwgbG9jaScsICdMb2YxMSBhbGwgbG9jaScsICdMb2YxNCBhbGwgbG9jaScsIAoJCQkJCSdDYW40MCBnYXRrIGxvY2knLCAnQ2FuMTQgZ2F0ayBsb2NpJywgJ0xvZjA3IGdhdGsgbG9jaScsICdMb2YxMSBnYXRrIGxvY2knLCAnTG9mMTQgZ2F0ayBsb2NpJywKCQkJCQknQ2FuNDAgZ2F0ayBubyBkYW0gbG9jaScsICdDYW4xNCBnYXRrIG5vIGRhbSBsb2NpJywgJ0xvZjA3IGdhdGsgbm8gZGFtIGxvY2knLCAnTG9mMTEgZ2F0ayBubyBkYW0gbG9jaScsIAoJCQkJCSdMb2YxNCBnYXRrIG5vIGRhbSBsb2NpJykKbmNocmxpc3QgPC0gbGlzdChuY2hyQ2FuNDAsIG5jaHJDYW4xNCwgbmNockxvZjA3LCBuY2hyTG9mMTEsIG5jaHJMb2YxNCwgbmNockNhbjQwLCBuY2hyQ2FuMTQsIG5jaHJMb2YwNywgbmNockxvZjExLCBuY2hyTG9mMTQsIG5jaHJDYW40MCwgbmNockNhbjE0LCBuY2hyTG9mMDcsIG5jaHJMb2YxMSwgbmNockxvZjE0KQoKdGhldGFib290b3V0IDwtIGRhdGEuZnJhbWUodHlwZSA9IG5hbWVzKGRhdGxpc3QpLCB0VyA9IE5BLCB0V2w5NSA9IE5BLCB0V3U5NSA9IE5BLCB0UCA9IE5BLCB0UGw5NSA9IE5BLCB0UHU5NSA9IE5BLCB0RCA9IE5BLCB0RGw5NSA9IE5BLCB0RHU5NSA9IE5BKQoKCiMjIyMjCgpsZ3MgPC0gZGF0Wywgc29ydCh1bmlxdWUoQ2hyb21vKSldCgpib290bGcgPC0gYm9vdChsZ3MsIHRoZXRhYmxvY2syLCBuYm9vdCwgIGFsbGRhdGEgPSBkYXQsIG5jaHIgPSBuY2hyLCByZWdzID0gcmVncykKCgpmb3IoaSBpbiAxOmxlbmd0aChkYXRsaXN0KSl7CglwcmludChuYW1lcyhkYXRsaXN0KVtpXSkKICAgIAogICAgCglib290bGcgPC0gYm9vdChsZ3MsIHRoZXRhYmxvY2ssIG5ib290LCAgYWxsZGF0YSA9IGRhdGxpc3RbW2ldXSwgbmNociA9IG5jaHJsaXN0W1tpXV0sIHJlZ3MgPSByZWdzKQoJCglwcmludChib290bGcpCgljaVcgPC0gYm9vdC5jaShib290bGcsIHR5cGUgPSBjKCdwZXJjJyksIGluZGV4ID0gMSkKCWNpUCA8LSBib290LmNpKGJvb3RsZywgdHlwZSA9IGMoJ3BlcmMnKSwgaW5kZXggPSAyKQoJY2lEIDwtIGJvb3QuY2koYm9vdGxnLCB0eXBlID0gYygncGVyYycpLCBpbmRleCA9IDMpCgkKCXRoZXRhYm9vdG91dCR0V1tpXSA8LSBib290bGckdDBbMV0gIyB0aGUgcG9pbnQgZXN0aW1hdGVzCgl0aGV0YWJvb3RvdXQkdFBbaV0gPC0gYm9vdGxnJHQwWzJdCQoJdGhldGFib290b3V0JHREW2ldIDwtIGJvb3RsZyR0MFszXQoKCXRoZXRhYm9vdG91dCR0V2w5NVtpXSA8LSBjaVckcGVyY2VudFs0XSAjIHRoZSBjb25maWRlbmNlIGludGVydmFscwoJdGhldGFib290b3V0JHRXdTk1W2ldIDwtIGNpVyRwZXJjZW50WzVdCgoJdGhldGFib290b3V0JHRQbDk1W2ldIDwtIGNpUCRwZXJjZW50WzRdCgl0aGV0YWJvb3RvdXQkdFB1OTVbaV0gPC0gY2lQJHBlcmNlbnRbNV0KCgl0aGV0YWJvb3RvdXQkdERsOTVbaV0gPC0gY2lEJHBlcmNlbnRbNF0KCXRoZXRhYm9vdG91dCR0RHU5NVtpXSA8LSBjaUQkcGVyY2VudFs1XQp9CgojIHNhdmUKd3JpdGUuY3N2KHRoZXRhYm9vdG91dCwgZmlsZSA9ICdhbmFseXNpcy90aGV0YXMuYm9vdC5jaXMuY3N2JykKCmBgYAoKCgoK